Ich habe eine relativ einfache Abfrage für eine Tabelle mit 1,5 Millionen Zeilen:
SELECT mtid FROM publication
WHERE mtid IN (9762715) OR last_modifier=21321
LIMIT 5000;
EXPLAIN ANALYZE
Ausgabe:
Limit (cost=8.84..12.86 rows=1 width=8) (actual time=0.985..0.986 rows=1 loops=1) -> Bitmap Heap Scan on publication (cost=8.84..12.86 rows=1 width=8) (actual time=0.984..0.985 rows=1 loops=1) Recheck Cond: ((mtid = 9762715) OR (last_modifier = 21321)) -> BitmapOr (cost=8.84..8.84 rows=1 width=0) (actual time=0.971..0.971 rows=0 loops=1) -> Bitmap Index Scan on publication_pkey (cost=0.00..4.42 rows=1 width=0) (actual time=0.295..0.295 rows=1 loops=1) Index Cond: (mtid = 9762715) -> Bitmap Index Scan on publication_last_modifier_btree (cost=0.00..4.42 rows=1 width=0) (actual time=0.674..0.674 rows=0 loops=1) Index Cond: (last_modifier = 21321) Total runtime: 1.027 ms
So weit so gut, schnell und nutzt die verfügbaren Indizes.
Wenn ich eine Abfrage nur ein wenig ändere, lautet das Ergebnis:
SELECT mtid FROM publication
WHERE mtid IN (SELECT 9762715) OR last_modifier=21321
LIMIT 5000;
Die EXPLAIN ANALYZE
Ausgabe ist:
Limit (cost=0.01..2347.74 rows=5000 width=8) (actual time=2735.891..2841.398 rows=1 loops=1) -> Seq Scan on publication (cost=0.01..349652.84 rows=744661 width=8) (actual time=2735.888..2841.393 rows=1 loops=1) Filter: ((hashed SubPlan 1) OR (last_modifier = 21321)) SubPlan 1 -> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.001 rows=1 loops=1) Total runtime: 2841.442 ms
Nicht so schnell und mit seq scan ...
Natürlich ist die ursprüngliche Abfrage, die von der Anwendung ausgeführt wird, etwas komplexer und sogar langsamer, und das im Ruhezustand generierte Original ist es natürlich nicht (SELECT 9762715)
, aber die Langsamkeit ist auch dafür da (SELECT 9762715)
! Die Abfrage wird im Ruhezustand generiert, daher ist es eine ziemliche Herausforderung, sie zu ändern, und einige Funktionen sind nicht verfügbar (z. B. UNION
nicht verfügbar, was schnell wäre).
Die Fragen
- Warum kann der Index im zweiten Fall nicht verwendet werden? Wie könnten sie verwendet werden?
- Kann ich die Abfrageleistung auf andere Weise verbessern?
Zusätzliche Gedanken
Es scheint, dass wir den ersten Fall verwenden könnten, indem wir manuell SELECT ausführen und dann die resultierende Liste in die Abfrage einfügen. Selbst mit 5000 Zahlen in der IN () -Liste ist es viermal schneller als die zweite Lösung. Es scheint jedoch nur FALSCH (außerdem könnte es 100-mal schneller sein :)). Es ist völlig unverständlich, warum der Abfrageplaner für diese beiden Abfragen eine völlig andere Methode verwendet. Daher möchte ich eine bessere Lösung für dieses Problem finden.
(SELECT 9762715)
.
(SELECT 9762715)
. Zur Frage zum Ruhezustand: Dies könnte durchgeführt werden, erfordert jedoch ein ernsthaftes Umschreiben des Codes, da wir benutzerdefinierte Kriterienabfragen für den Ruhezustand haben, die im laufenden Betrieb übersetzt werden. Im Wesentlichen würden wir also den Ruhezustand ändern, was ein großes Unterfangen mit vielen möglichen Nebenwirkungen ist.
JOIN
anstelle des generiertIN ()
? Außerdem wurdepublication
kürzlich analysiert?