perf(db): kasuje ix_scenes_title_normalized, zbedny prefiks indeksu z 0039
ix_scenes_title_created_id_desc zaczyna sie od tej samej kolumny, wiec obsluguje wszystko,
co obslugiwal stary indeks: lookupy `title_normalized = X` z resolvera i skan 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 tam caly czas.
Sprawdzone na produkcji przez BEGIN; DROP INDEX; EXPLAIN ANALYZE; ROLLBACK, zeby zobaczyc
wybor planera bez starego indeksu, a potem jeszcze raz po samym dropie:
exact title lookup 1,76 ms -> 0,07 ms, Index Scan po nowym indeksie
OR studio + exact title ten sam ksztalt planu (BitmapOr), 3,7 ms
OR data + exact title Seq Scan przy szerokim oknie dat, ale to decyzja o release_date:
z enable_seqscan=off BitmapOr siega po nowy indeks
trgm ILIKE bez zmian, swoj indeks GIN
W wariancie z OR planer i tak siegal juz po nowy indeks, jeszcze zanim stary znikl.
Indeksy scenes: 3544 MB -> 3177 MB. Listy scen po dropie bez zmian (tytul 22-54 ms,
studio 38-73 ms na stronach 1-5).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
470beb4aa6
commit
b6a075b28a
3 changed files with 55 additions and 7 deletions
|
|
@ -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
|
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.
|
(ASC, DESC, DESC) i inaczej skan nie przejdzie po kolei.
|
||||||
|
|
||||||
`ix_scenes_title_normalized` zostaje: sluzy tez zwyklym lookupom po tytule (2,2 mln
|
Ten indeks zaczyna sie od `title_normalized`, wiec obsluguje tez zwykle lookupy po tytule
|
||||||
skanow), a odpiecie go od tego indeksu to osobna decyzja, nie skutek uboczny tej migracji.
|
(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
|
CONCURRENTLY w autocommit_block, jak w 0035 i 0038. Nieudany CONCURRENTLY zostawia indeks
|
||||||
INVALID; wtedy DROP INDEX i ponownie.
|
INVALID; wtedy DROP INDEX i ponownie.
|
||||||
|
|
|
||||||
|
|
@ -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)"
|
||||||
|
)
|
||||||
|
|
@ -608,11 +608,12 @@ def list_scenes(
|
||||||
)
|
)
|
||||||
elif sort == "title":
|
elif sort == "title":
|
||||||
# Cale ORDER BY (razem z tie-breakami) pokrywa ix_scenes_title_created_id_desc
|
# Cale ORDER BY (razem z tie-breakami) pokrywa ix_scenes_title_created_id_desc
|
||||||
# (migracja 0039). Sam `ix_scenes_title_normalized` zostawial Postgresowi
|
# (migracja 0039). Wczesniejszy indeks na samym `title_normalized` zostawial
|
||||||
# Incremental Sort, ktory przed oddaniem czegokolwiek MUSI zebrac caly kubelek
|
# Postgresowi Incremental Sort, a ten przed oddaniem czegokolwiek MUSI zebrac caly
|
||||||
# o tym samym tytule: na stronie 1 glownego feedu ciagnal 1084 wiersze zamiast
|
# kubelek scen o tym samym tytule: na stronie 1 glownego feedu ciagnal 1084 wiersze
|
||||||
# 51 (709 ms), a z filtrem taga szedl w minuty. Z pelnym indeksem sortu nie ma
|
# zamiast 51 (709 ms), a z filtrem taga szedl w minuty. Z pelnym indeksem wezla
|
||||||
# wcale, skan urywa sie na 51. wierszu (5-12 ms).
|
# 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(
|
ordered = base.order_by(
|
||||||
Scene.title_normalized.asc(), Scene.created_at.desc(), Scene.id.desc()
|
Scene.title_normalized.asc(), Scene.created_at.desc(), Scene.id.desc()
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue