perf(db): drop 10 redundant single-column FK indexes (R12 S5)
Each column already leads a composite UNIQUE constraint whose btree covers leftmost-prefix lookups on it (and the ON DELETE CASCADE reverse lookups), so the extra single-column index=True was pure write-amplification. Drop index=True on the 10 columns + alembic 0062 drops the existing indexes (DROP INDEX IF EXISTS; downgrade recreates). Verified: migration up/down round-trips on localdev (10 indexes drop, composites intact), siftlode check green (alembic upgrade head incl. 0062 + pytest 193). The 10 do not appear in an alembic-check model/DB diff → models and migration agree.
This commit is contained in:
@@ -0,0 +1,53 @@
|
|||||||
|
"""drop 10 redundant single-column FK indexes (R12 S5)
|
||||||
|
|
||||||
|
Each of these columns already leads a composite UNIQUE constraint, whose btree covers leftmost-prefix
|
||||||
|
lookups on that column (and the ON DELETE CASCADE reverse lookups too) — so the extra single-column
|
||||||
|
`index=True` was pure write-amplification. Dropping them costs nothing on reads and saves an index
|
||||||
|
write per insert/update. Fast (index-only drop, no table rewrite). Reversible (downgrade recreates).
|
||||||
|
|
||||||
|
Redundant index -> the composite that already covers it:
|
||||||
|
ix_subscriptions_user_id <- uq_user_channel (user_id, channel_id)
|
||||||
|
ix_video_states_user_id <- uq_user_video (user_id, video_id)
|
||||||
|
ix_search_finds_user_id <- uq_user_search_video (user_id, video_id)
|
||||||
|
ix_explored_channels_user_id <- uq_user_explored_channel (user_id, channel_id)
|
||||||
|
ix_blocked_channels_user_id <- uq_user_blocked_channel (user_id, channel_id)
|
||||||
|
ix_saved_views_user_id <- uq_user_saved_view (user_id, name)
|
||||||
|
ix_playlist_items_playlist_id <- uq_playlist_video (playlist_id, video_id)
|
||||||
|
ix_download_shares_job_id <- uq_download_share (job_id, to_user_id)
|
||||||
|
ix_plex_states_user_id <- uq_plex_user_item (user_id, item_id)
|
||||||
|
ix_plex_playlist_items_playlist_id <- uq_plex_playlist_item (playlist_id, item_id)
|
||||||
|
"""
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
revision: str = "0062_drop_redundant_idx"
|
||||||
|
down_revision: Union[str, None] = "0061_dl_job_error_code"
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
# (index_name, table_name, column)
|
||||||
|
_REDUNDANT: list[tuple[str, str, str]] = [
|
||||||
|
("ix_subscriptions_user_id", "subscriptions", "user_id"),
|
||||||
|
("ix_video_states_user_id", "video_states", "user_id"),
|
||||||
|
("ix_search_finds_user_id", "search_finds", "user_id"),
|
||||||
|
("ix_explored_channels_user_id", "explored_channels", "user_id"),
|
||||||
|
("ix_blocked_channels_user_id", "blocked_channels", "user_id"),
|
||||||
|
("ix_saved_views_user_id", "saved_views", "user_id"),
|
||||||
|
("ix_playlist_items_playlist_id", "playlist_items", "playlist_id"),
|
||||||
|
("ix_download_shares_job_id", "download_shares", "job_id"),
|
||||||
|
("ix_plex_states_user_id", "plex_states", "user_id"),
|
||||||
|
("ix_plex_playlist_items_playlist_id", "plex_playlist_items", "playlist_id"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
for idx, table, _col in _REDUNDANT:
|
||||||
|
# IF EXISTS: a DB whose schema was stamped from a create_all (tests) won't have these once
|
||||||
|
# the models drop index=True, so a plain drop_index would error there.
|
||||||
|
op.execute(f"DROP INDEX IF EXISTS {idx}")
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
for idx, table, col in _REDUNDANT:
|
||||||
|
op.create_index(idx, table, [col])
|
||||||
+10
-10
@@ -219,7 +219,7 @@ class Subscription(Base, TimestampMixin):
|
|||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
user_id: Mapped[int] = mapped_column(
|
user_id: Mapped[int] = mapped_column(
|
||||||
ForeignKey("users.id", ondelete="CASCADE"), index=True
|
ForeignKey("users.id", ondelete="CASCADE")
|
||||||
)
|
)
|
||||||
channel_id: Mapped[str] = mapped_column(
|
channel_id: Mapped[str] = mapped_column(
|
||||||
ForeignKey("channels.id", ondelete="CASCADE"), index=True
|
ForeignKey("channels.id", ondelete="CASCADE"), index=True
|
||||||
@@ -388,7 +388,7 @@ class VideoState(Base, UpdatedAtMixin):
|
|||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
user_id: Mapped[int] = mapped_column(
|
user_id: Mapped[int] = mapped_column(
|
||||||
ForeignKey("users.id", ondelete="CASCADE"), index=True
|
ForeignKey("users.id", ondelete="CASCADE")
|
||||||
)
|
)
|
||||||
video_id: Mapped[str] = mapped_column(
|
video_id: Mapped[str] = mapped_column(
|
||||||
ForeignKey("videos.id", ondelete="CASCADE"), index=True
|
ForeignKey("videos.id", ondelete="CASCADE"), index=True
|
||||||
@@ -418,7 +418,7 @@ class SearchFind(Base, TimestampMixin):
|
|||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
user_id: Mapped[int] = mapped_column(
|
user_id: Mapped[int] = mapped_column(
|
||||||
ForeignKey("users.id", ondelete="CASCADE"), index=True
|
ForeignKey("users.id", ondelete="CASCADE")
|
||||||
)
|
)
|
||||||
video_id: Mapped[str] = mapped_column(
|
video_id: Mapped[str] = mapped_column(
|
||||||
ForeignKey("videos.id", ondelete="CASCADE"), index=True
|
ForeignKey("videos.id", ondelete="CASCADE"), index=True
|
||||||
@@ -443,7 +443,7 @@ class ExploredChannel(Base, TimestampMixin):
|
|||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
user_id: Mapped[int] = mapped_column(
|
user_id: Mapped[int] = mapped_column(
|
||||||
ForeignKey("users.id", ondelete="CASCADE"), index=True
|
ForeignKey("users.id", ondelete="CASCADE")
|
||||||
)
|
)
|
||||||
channel_id: Mapped[str] = mapped_column(
|
channel_id: Mapped[str] = mapped_column(
|
||||||
ForeignKey("channels.id", ondelete="CASCADE"), index=True
|
ForeignKey("channels.id", ondelete="CASCADE"), index=True
|
||||||
@@ -462,7 +462,7 @@ class BlockedChannel(Base, TimestampMixin):
|
|||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
user_id: Mapped[int] = mapped_column(
|
user_id: Mapped[int] = mapped_column(
|
||||||
ForeignKey("users.id", ondelete="CASCADE"), index=True
|
ForeignKey("users.id", ondelete="CASCADE")
|
||||||
)
|
)
|
||||||
channel_id: Mapped[str] = mapped_column(
|
channel_id: Mapped[str] = mapped_column(
|
||||||
ForeignKey("channels.id", ondelete="CASCADE"), index=True
|
ForeignKey("channels.id", ondelete="CASCADE"), index=True
|
||||||
@@ -619,7 +619,7 @@ class PlaylistItem(Base):
|
|||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
playlist_id: Mapped[int] = mapped_column(
|
playlist_id: Mapped[int] = mapped_column(
|
||||||
ForeignKey("playlists.id", ondelete="CASCADE"), index=True
|
ForeignKey("playlists.id", ondelete="CASCADE")
|
||||||
)
|
)
|
||||||
video_id: Mapped[str] = mapped_column(
|
video_id: Mapped[str] = mapped_column(
|
||||||
ForeignKey("videos.id", ondelete="CASCADE"), index=True
|
ForeignKey("videos.id", ondelete="CASCADE"), index=True
|
||||||
@@ -644,7 +644,7 @@ class SavedView(Base, TimestampMixin, UpdatedAtMixin):
|
|||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
user_id: Mapped[int] = mapped_column(
|
user_id: Mapped[int] = mapped_column(
|
||||||
ForeignKey("users.id", ondelete="CASCADE"), index=True
|
ForeignKey("users.id", ondelete="CASCADE")
|
||||||
)
|
)
|
||||||
name: Mapped[str] = mapped_column(String(80))
|
name: Mapped[str] = mapped_column(String(80))
|
||||||
filters: Mapped[dict] = mapped_column(JSON)
|
filters: Mapped[dict] = mapped_column(JSON)
|
||||||
@@ -893,7 +893,7 @@ class DownloadShare(Base, TimestampMixin):
|
|||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
job_id: Mapped[int] = mapped_column(
|
job_id: Mapped[int] = mapped_column(
|
||||||
ForeignKey("download_jobs.id", ondelete="CASCADE"), index=True
|
ForeignKey("download_jobs.id", ondelete="CASCADE")
|
||||||
)
|
)
|
||||||
from_user_id: Mapped[int] = mapped_column(
|
from_user_id: Mapped[int] = mapped_column(
|
||||||
ForeignKey("users.id", ondelete="CASCADE"), index=True
|
ForeignKey("users.id", ondelete="CASCADE"), index=True
|
||||||
@@ -1191,7 +1191,7 @@ class PlexState(Base, UpdatedAtMixin):
|
|||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
user_id: Mapped[int] = mapped_column(
|
user_id: Mapped[int] = mapped_column(
|
||||||
ForeignKey("users.id", ondelete="CASCADE"), index=True
|
ForeignKey("users.id", ondelete="CASCADE")
|
||||||
)
|
)
|
||||||
item_id: Mapped[int] = mapped_column(
|
item_id: Mapped[int] = mapped_column(
|
||||||
ForeignKey("plex_items.id", ondelete="CASCADE"), index=True
|
ForeignKey("plex_items.id", ondelete="CASCADE"), index=True
|
||||||
@@ -1260,7 +1260,7 @@ class PlexPlaylistItem(Base):
|
|||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
playlist_id: Mapped[int] = mapped_column(
|
playlist_id: Mapped[int] = mapped_column(
|
||||||
ForeignKey("plex_playlists.id", ondelete="CASCADE"), index=True
|
ForeignKey("plex_playlists.id", ondelete="CASCADE")
|
||||||
)
|
)
|
||||||
item_id: Mapped[int] = mapped_column(
|
item_id: Mapped[int] = mapped_column(
|
||||||
ForeignKey("plex_items.id", ondelete="CASCADE"), index=True
|
ForeignKey("plex_items.id", ondelete="CASCADE"), index=True
|
||||||
|
|||||||
Reference in New Issue
Block a user