Zdravím, prosím o nějakou radu k problému, co se mi vyskytl.
Mám funkci, která dělá zhruba toto:
- na vstupu je XML soubor
- funkce se podívá, jaký časový úsek v XML je, tento smaže z databáze a nahradí ho novým, který získá zpracováním vstupu (mění se obsah jediné tabulky)
- na závěr udělá select, který vrátí, co je v právě vložených datech „navíc“ (hned při vkládání se to poznat nedá, je potřeba se pak na to podívat jako na celek) a tyto řádky se smažou (oproti všem vloženým datům je jich malý zlomek)
Ve verzi 9.1 to fungovalo dobře, při upgrade na 9.2 (konkrétně jsem zkoušel 9.2.2 a 9.2.3 – je to stejné) je ale funkce výrazně pomalejší.
Po prozkoumání jsem zjistil, že za to může ten poslední krok, který hledá ty přebytečné řádky. „Rychlá“ varianta trvá okolo 100ms, „pomalá“ asi 90s. Nejprve jsem podezříval mazání (je tam trigr), ale není to tak, pomalé je to zjištění, co se má smazat (ten select není úplně triviální, používá funkci, která je napsaná rekurzivně - nemůže to být stopa?).
Zvláštní je, že takhle pomalé je to jenom v té funkci – když tuhle část z funkce odstraním a po jejím doběhnutí zavolám zvlášť, je to rychlé.
Další zajímavá věc na kterou jsem přišel je ta, že když si tuto část dám do jiné funkce a tu volám 2×, jednou před zpracováním dat a podruhé po, projdou rychle obě. Pokud ji ale volám jenom po, je to pomalé.
Mám prováděcí plány, ale moc je neumím číst. Dokáže z toho prosím někdo zjistit, kde je problém a hlavně co změnit, aby to zase chodilo rychle?
Díky předem.
Rychlá verze:
Sort (cost=1951.82..1951.87 rows=18 width=8)
Sort Key: i."Index"
CTE pl
-> HashAggregate (cost=172.20..172.44 rows=24 width=8)
-> Seq Scan on pl_sync (cost=0.00..172.14 rows=24 width=8)
Filter: (date IS NOT NULL)
-> HashAggregate (cost=1778.78..1779.00 rows=18 width=8)
-> Hash Join (cost=189.03..1777.18 rows=320 width=8)
Hash Cond: (i."Date" = pl.date)
-> Hash Join (cost=188.25..1763.99 rows=2457 width=16)
Hash Cond: (i."SSectionID" = s."ID")
-> Seq Scan on "PL_items" i (cost=186.36..1637.72 rows=26615 width=20)
Filter: (NOT (hashed SubPlan 2))
SubPlan 2
-> CTE Scan on pl (cost=0.00..126.36 rows=24000 width=8)
-> Hash (cost=1.81..1.81 rows=6 width=4)
-> Seq Scan on "PL_station_sections" s (cost=0.00..1.81 rows=6 width=4)
Filter: ("StationID" = 3)
-> Hash (cost=0.48..0.48 rows=24 width=8)
-> CTE Scan on pl (cost=0.00..0.48 rows=24 width=8)
Pomalá verze:
Sort (cost=5522830.04..5522830.08 rows=18 width=8)
Sort Key: i."Index"
CTE pl
-> HashAggregate (cost=291.68..293.68 rows=200 width=8)
-> Seq Scan on pl_sync (cost=0.00..265.65 rows=10413 width=8)
Filter: (date IS NOT NULL)
-> HashAggregate (cost=5522535.76..5522535.98 rows=18 width=8)
-> Nested Loop (cost=0.00..5522523.47 rows=2457 width=8)
Join Filter: (i."Date" = pl.date)
-> CTE Scan on pl (cost=0.00..4.00 rows=200 width=8)
-> Materialize (cost=0.00..5515154.61 rows=2457 width=16)
-> Nested Loop (cost=0.00..5515142.33 rows=2457 width=16)
-> Seq Scan on "PL_station_sections" s (cost=0.00..1.81 rows=6 width=4)
Filter: ("StationID" = 3)
-> Index Scan using "PL_items_idx" on "PL_items" i (cost=0.00..919184.18 rows=591 width=20)
Index Cond: ("SSectionID" = s."ID")
Filter: (NOT (SubPlan 2))
SubPlan 2
-> CTE Scan on pl (cost=0.00..1053.00 rows=200000 width=8)
postgres=# explain with pl as (select distinct a from x)
select foo(a) from pl;
QUERY PLAN
───────────────────────────────────────────────────────────────────
CTE Scan on pl (cost=18.39..486.98 rows=89000 width=4)
CTE pl
-> HashAggregate (cost=17.50..18.39 rows=89 width=4)
-> Seq Scan on x (cost=0.00..15.00 rows=1000 width=4)
(4 rows)
tady je extremne dulezite, aby ROWS u SRF funkce bylo adekvatni, kdyz
se to pouzije takto.