Wie zwinge ich Postgres, einen Index zu verwenden, wenn es sonst darauf bestehen würde, einen sequentiellen Scan durchzuführen?
sql
postgresql
indexing
Mikrofon
quelle
quelle
Antworten:
Angenommen, Sie fragen nach der allgemeinen Funktion "Indexhinweise", die in vielen Datenbanken zu finden ist, bietet PostgreSQL eine solche Funktion nicht an. Dies war eine bewusste Entscheidung des PostgreSQL-Teams. Eine gute Übersicht darüber, warum und was Sie stattdessen tun können, finden Sie hier . Die Gründe dafür sind im Grunde, dass es sich um einen Performance-Hack handelt, der später zu weiteren Problemen führt, wenn sich Ihre Daten ändern, während der Optimierer von PostgreSQL den Plan basierend auf den Statistiken neu bewerten kann. Mit anderen Worten, was heute ein guter Abfrageplan sein könnte, wird wahrscheinlich nicht für alle Zeiten ein guter Abfrageplan sein, und Indexhinweise erzwingen einen bestimmten Abfrageplan für alle Zeiten.
Als sehr stumpfer Hammer, der zum Testen nützlich ist, können Sie die Parameter
enable_seqscan
und verwendenenable_indexscan
. Sehen:enable_
ParameterDiese sind nicht für den laufenden Produktionseinsatz geeignet . Wenn Sie Probleme mit der Auswahl des Abfrageplans haben, sollten Sie die Dokumentation zum Aufspüren von Problemen mit der Abfrageleistung lesen .
enable_
Stellen Sie nicht nur Parameter ein und gehen Sie weg.Wenn Sie keinen guten Grund für die Verwendung des Index haben, trifft Postgres möglicherweise die richtige Wahl. Warum?
Siehe auch diesen alten Newsgroup-Beitrag .
quelle
Wahrscheinlich der einzig gültige Grund für die Verwendung
Dies ist der Fall, wenn Sie Abfragen schreiben und schnell sehen möchten, wie der Abfrageplan tatsächlich aussehen würde, wenn große Datenmengen in den Tabellen enthalten wären. Oder natürlich, wenn Sie schnell bestätigen müssen, dass Ihre Abfrage keinen Index verwendet, nur weil der Datensatz zu klein ist.
quelle
set enable_seqscan=false
, Ausführen Ihrer Abfrage und dann schnell ausführenset enable_seqscan=true
, um postgresql wieder in das richtige Verhalten zu versetzen (und dies natürlich nicht in der Produktion, sondern nur in der Entwicklung!)SET SESSION enable_seqscan=false
nur sich selbst zu beeinflussenManchmal trifft PostgreSQL nicht die beste Auswahl an Indizes für eine bestimmte Bedingung. Angenommen, es gibt eine Transaktionstabelle mit mehreren Millionen Zeilen, von denen es für einen bestimmten Tag mehrere Hundert gibt, und die Tabelle enthält vier Indizes: transaction_id, client_id, date und description. Sie möchten die folgende Abfrage ausführen:
PostgreSQL verwendet möglicherweise den Index transaction_description_idx anstelle von transaction_date_idx. Dies kann dazu führen, dass die Abfrage mehrere Minuten statt weniger als einer Sekunde dauert. Wenn dies der Fall ist, können Sie die Verwendung des Index am Datum erzwingen, indem Sie die Bedingung wie folgt verfälschen:
quelle
your_wanted_index
. Es kann daher sein, dass die postgresql-Engine stattdessen nur einen Sequenz- / Primärschlüssel-Scan durchführt. Schlussfolgerung - Es gibt keine 100% zuverlässige Methode, um eine Indexverwendung für den PostgreSql-Server zu erzwingen.where
Bedingung außer zwei Tabellen oder verknüpften gibt und Postgres den Index nicht übernimmt ?Kurze Antwort
Dieses Problem tritt normalerweise auf, wenn die geschätzten Kosten eines Index-Scans zu hoch sind und die Realität nicht korrekt widerspiegeln. Möglicherweise müssen Sie den
random_page_cost
Konfigurationsparameter verringern, um dies zu beheben. Aus der Postgres-Dokumentation :Sie können überprüfen, ob ein niedrigerer Wert tatsächlich dazu führt, dass Postgres den Index verwendet (dies wird jedoch nur zum Testen verwendet ):
Sie können den Standardwert mit
SET random_page_cost = DEFAULT;
wieder herstellen.Hintergrund
Index-Scans erfordern nicht sequentielle Abrufe von Festplattenseiten. Postgres verwendet
random_page_cost
, um die Kosten solcher nicht sequentiellen Abrufe im Verhältnis zu sequentiellen Abrufen zu schätzen. Der Standardwert ist4.0
, wobei ein durchschnittlicher Kostenfaktor von 4 im Vergleich zu sequentiellen Abrufen angenommen wird (unter Berücksichtigung von Caching-Effekten).Das Problem ist jedoch, dass dieser Standardwert in den folgenden wichtigen realen Szenarien ungeeignet ist:
1) Solid-State-Laufwerke
Wie die Dokumentation zugibt:
Laut dem letzten Punkt dieser Folie aus einem Vortrag auf der PostgresConf 2018
random_page_cost
sollte auf etwas zwischen1.0
und2.0
für Solid-State-Laufwerke eingestellt werden.2) Zwischengespeicherte Daten
Wenn die erforderlichen Indexdaten bereits im RAM zwischengespeichert sind, ist ein Index-Scan immer erheblich schneller als ein sequentieller Scan. Die Dokumentation sagt:
Das Problem ist, dass Sie natürlich nicht leicht wissen können, ob die relevanten Daten bereits zwischengespeichert sind. Wenn jedoch häufig ein bestimmter Index abgefragt wird und das System über ausreichend RAM verfügt, werden die Daten wahrscheinlich zwischengespeichert und
random_page_cost
sollten auf einen niedrigeren Wert gesetzt werden. Sie müssen mit verschiedenen Werten experimentieren und sehen, was für Sie funktioniert.Möglicherweise möchten Sie auch die Erweiterung pg_prewarm für das explizite Zwischenspeichern von Daten verwenden.
quelle
Die Frage an sich ist sehr ungültig. Das Erzwingen (zum Beispiel durch enable_seqscan = off) ist eine sehr schlechte Idee. Es kann nützlich sein zu überprüfen, ob es schneller sein wird, aber Produktionscode sollte niemals solche Tricks verwenden.
Erklären Sie stattdessen die Analyse Ihrer Abfrage, lesen Sie sie und finden Sie heraus, warum PostgreSQL (Ihrer Meinung nach) einen schlechten Plan wählt.
Es gibt Tools im Web, die beim Lesen helfen, die Analyse zu erklären - eine davon ist EXPLAIN.depesz.com - von mir geschrieben.
Eine andere Möglichkeit besteht darin, sich dem # postgresql-Kanal im freenode irc-Netzwerk anzuschließen und mit den dortigen Mitarbeitern zu sprechen, um Ihnen zu helfen. Bei der Optimierung der Abfrage geht es nicht darum, "eine Frage zu stellen, eine Antwort zu erhalten, glücklich zu sein". Es ist eher ein Gespräch, bei dem viele Dinge überprüft und viele Dinge gelernt werden müssen.
quelle
Es gibt einen Trick, um Postgres zu verschieben, um einen Seqscan zu bevorzugen, der ein
OFFSET 0
in der Unterabfrage hinzufügtDies ist praktisch, um Anforderungen zu optimieren, die große / große Tabellen verknüpfen, wenn Sie nur die n ersten / letzten Elemente benötigen.
Nehmen wir an, Sie suchen nach den ersten / letzten 20 Elementen mit mehreren Tabellen mit 100.000 (oder mehr) Einträgen. Es macht keinen Sinn, die gesamte Abfrage über alle Daten hinweg aufzubauen / zu verknüpfen, wenn das, wonach Sie suchen, in den ersten 100 oder 1000 liegt Einträge. In diesem Szenario ist es beispielsweise mehr als zehnmal schneller, einen sequentiellen Scan durchzuführen.
Siehe Wie kann ich verhindern, dass Postgres eine Unterabfrage einfügt?
quelle