diff --git a/alembic/versions/20260916_0039_scenes_title_created_id_idx.py b/alembic/versions/20260916_0039_scenes_title_created_id_idx.py index e60c9fa..cce3d28 100644 --- a/alembic/versions/20260916_0039_scenes_title_created_id_idx.py +++ b/alembic/versions/20260916_0039_scenes_title_created_id_idx.py @@ -15,8 +15,9 @@ Pomiar na produkcji 2026-09-16, ten sam zestaw filtrow, po rozgrzewce: Kierunki w indeksie musza byc dokladnie takie jak w ORDER BY, bo sort jest mieszany (ASC, DESC, DESC) i inaczej skan nie przejdzie po kolei. -`ix_scenes_title_normalized` zostaje: sluzy tez zwyklym lookupom po tytule (2,2 mln -skanow), a odpiecie go od tego indeksu to osobna decyzja, nie skutek uboczny tej migracji. +Ten indeks zaczyna sie od `title_normalized`, wiec obsluguje tez zwykle lookupy po tytule +(2,2 mln skanow), przez ktore stary `ix_scenes_title_normalized` staje sie zbedny. Usuwa go +migracja 0040, osobno, zeby dalo sie cofnac samo usuniecie. CONCURRENTLY w autocommit_block, jak w 0035 i 0038. Nieudany CONCURRENTLY zostawia indeks INVALID; wtedy DROP INDEX i ponownie. diff --git a/alembic/versions/20260916_0040_drop_scenes_title_normalized_idx.py b/alembic/versions/20260916_0040_drop_scenes_title_normalized_idx.py new file mode 100644 index 0000000..7b751e7 --- /dev/null +++ b/alembic/versions/20260916_0040_drop_scenes_title_normalized_idx.py @@ -0,0 +1,46 @@ +"""Usuwa ix_scenes_title_normalized, zastapiony prefiksem indeksu z 0039. + +`ix_scenes_title_created_id_desc (title_normalized, created_at DESC, id DESC)` zaczyna sie +od tej samej kolumny, wiec obsluguje wszystko, co obslugiwal stary indeks: lookupy +`title_normalized = X` z resolvera (`scene_match.blocking_candidates`, +`scene_resolver` przy trybie agregatora) i skanowanie zakresu przy sortowaniu po tytule. +Trzymanie obu to 367 MB na dysku i jeden indeks wiecej do utrzymania przy kazdym zapisie +do `scenes`, a ingest pisze do tej tabeli caly czas. + +Sprawdzone na produkcji 2026-09-16 przez `BEGIN; DROP INDEX ...; EXPLAIN ANALYZE ...; +ROLLBACK;`, zeby zobaczyc wybor planera bez starego indeksu: + + exact title lookup Index Scan ix_scenes_title_normalized 1,76 ms + -> Index Scan ix_scenes_title_created_id_desc 0,05 ms + OR studio + exact title Bitmap Index Scan, ten sam ksztalt planu + +W wariancie z OR planer i tak siegal juz po nowy indeks, jeszcze zanim stary znikl. + +CONCURRENTLY w autocommit_block: DROP bez CONCURRENTLY bierze ACCESS EXCLUSIVE i zatrzymuje +ingest na czas operacji. + +Revision ID: 0040_drop_scenes_title_norm_idx +Revises: 0039_scenes_title_created_id_idx +Create Date: 2026-09-16 +""" +from __future__ import annotations + +from alembic import op + +revision = "0040_drop_scenes_title_norm_idx" +down_revision: str | None = "0039_scenes_title_created_id_idx" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + with op.get_context().autocommit_block(): + op.execute("DROP INDEX CONCURRENTLY IF EXISTS ix_scenes_title_normalized") + + +def downgrade() -> None: + with op.get_context().autocommit_block(): + op.execute( + "CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_scenes_title_normalized " + "ON scenes (title_normalized)" + ) diff --git a/app/api/scenes.py b/app/api/scenes.py index 66dbb47..03bb09c 100644 --- a/app/api/scenes.py +++ b/app/api/scenes.py @@ -608,11 +608,12 @@ def list_scenes( ) elif sort == "title": # Cale ORDER BY (razem z tie-breakami) pokrywa ix_scenes_title_created_id_desc - # (migracja 0039). Sam `ix_scenes_title_normalized` zostawial Postgresowi - # Incremental Sort, ktory przed oddaniem czegokolwiek MUSI zebrac caly kubelek - # o tym samym tytule: na stronie 1 glownego feedu ciagnal 1084 wiersze zamiast - # 51 (709 ms), a z filtrem taga szedl w minuty. Z pelnym indeksem sortu nie ma - # wcale, skan urywa sie na 51. wierszu (5-12 ms). + # (migracja 0039). Wczesniejszy indeks na samym `title_normalized` zostawial + # Postgresowi Incremental Sort, a ten przed oddaniem czegokolwiek MUSI zebrac caly + # kubelek scen o tym samym tytule: na stronie 1 glownego feedu ciagnal 1084 wiersze + # zamiast 51 (709 ms), a z filtrem taga szedl w minuty. Z pelnym indeksem wezla + # sortu nie ma wcale, skan urywa sie na 51. wierszu (5-12 ms). Stary indeks byl + # prefiksem nowego, wiec 0040 go kasuje. ordered = base.order_by( Scene.title_normalized.asc(), Scene.created_at.desc(), Scene.id.desc() )