Indizierung des Zustands eines Teilindex in Postgres

Sep 05 2020

Ich versuche zu überlegen, wie Postgres-Teilindizes in Postgres gespeichert werden. Angenommen, ich erstelle einen solchen Index

CREATE INDEX orders_unbilled_index ON orders (order_nr)
WHERE billed is not true

um schnell eine Abfrage wie auszuführen

SELECT *
FROM orders
WHERE billed is not true AND order_nr > 1000000

Postgres speichert offensichtlich einen Index für order_nreine Teilmenge der ordersTabelle, wie durch den bedingten Ausdruck definiert billed is not true. Ich habe jedoch einige Fragen dazu:

  1. Speichert Postgres einen anderen Index intern billed is not true, um die mit dem Teilindex verknüpften Zeilen schnell zu finden?
  2. Wenn (1) nicht der Fall ist, würde die obige Abfrage dann schneller ausgeführt, wenn ich einen separaten Index für erstellen würde billed is not true? (unter der Annahme einer großen Tabelle und weniger Zeilen mit billed is true)

BEARBEITEN: Meine Beispielabfrage basierend auf den Dokumenten ist nicht die beste, da boolesche Indizes selten verwendet werden. Bitte betrachten Sie meine Fragen im Kontext eines bedingten Ausdrucks.

Antworten

2 LaurenzAlbe Sep 06 2020 at 12:08

Ein B-Tree-Index kann als geordnete Liste von Indexeinträgen mit jeweils einem Zeiger auf eine Zeile in der Tabelle betrachtet werden.

In einem Teilindex ist die Liste nur kleiner: Es gibt nur Indexeinträge für Zeilen, die die Bedingung erfüllen.

Wenn Sie die Indexbedingung in Ihrer WHEREKlausel haben, weiß PostgreSQL, dass es den Index verwenden kann, und muss die Indexbedingung nicht überprüfen, da sie automatisch erfüllt wird.

Damit:

  1. Nein, jede über den Index gefundene Zeile erfüllt automatisch die Indexbedingung. Die Verwendung des Index reicht also aus, um sicherzustellen, dass er erfüllt ist.

  2. Nein, ein Index für eine boolesche Spalte wird nicht verwendet, da er nicht billiger als dieser Teilindex wäre und der Teilindex auch zum Überprüfen der Bedingung verwendet werden kann order_nr.

    Es ist eigentlich umgekehrt: Der Teilindex kann durchaus für Abfragen verwendet werden, bei denen die booleanSpalte nur in der WHEREBedingung enthalten ist, wenn nur wenige Zeilen vorhanden sind, die die Bedingung erfüllen.

TimBiegeleisen Sep 06 2020 at 04:39

Nach meinem Verständnis erstellt Postgres einfach einen Index, der nur zum Nachschlagen von Datensätzen verwendet werden kann, die billedals nicht wahr gelten. Das heißt, der resultierende B-Baum würde von der indiziert order_nr, würde aber nur dann auf die ursprüngliche Tabelle zurückgreifen, wenn billeder falsch ist.

Wenn Sie die Dokumentation unmittelbar nach dem, was Sie zitiert haben, weiterlesen, finden Sie die folgende Abfrage als Beispiel:

SELECT * FROM orders WHERE billed is not true AND amount > 5000.00;

Es ist der Fall, dass Postgres möglicherweise sogar den Index verwendet, den Sie in der obigen Abfrage definiert haben. Es kann Ihren Index verwenden, um diese Abfrage zu erfüllen, indem der gesamte Index gescannt wird. Wenn es eine relativ kleine Anzahl von Aufträgen gibt, die noch nicht in Rechnung gestellt wurden, ist das Scannen des Index order_nrmöglicherweise immer noch einem vollständigen Tabellenscan vorzuziehen.

Die Antwort auf Ihre Frage Nr. 1 lautet also: Nein, es gibt keinen separaten Index für billed, sondern der Index für order_nrkann nur für Datensätze verwendet werden, billeddie auf false gesetzt wurden. Und für # 2 billed is not truekönnte ein zweiter Index verwendet werden, vorausgesetzt, nur wenige Datensätze werden nicht in Rechnung gestellt. Möglicherweise wird jedoch auch Ihr aktueller Index unverändert verwendet.