PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Wie ist die Reihenfolge der Datensätze in einer Tabelle mit einem zusammengesetzten Primärschlüssel?

Diese Frage macht die fehlgeleitete Annahme, dass der Primärschlüssel überhaupt eine Tabellenreihenfolge auferlegt. Das tut es nicht. PostgreSQL-Tabellen haben keine definierte Reihenfolge, mit oder ohne Primärschlüssel; Sie sind ein "Haufen" von Zeilen, die in Seitenblöcken angeordnet sind. Die Bestellung wird mit dem ORDER BY auferlegt Klausel von Abfragen, wenn gewünscht.

Sie denken vielleicht, dass PostgreSQL-Tabellen als indexorientierte Tabellen gespeichert werden, die in der Reihenfolge der Primärschlüssel auf der Festplatte gespeichert werden, aber so funktioniert Pg nicht. Ich denke, InnoDB speichert Tabellen, die nach dem Primärschlüssel organisiert sind (aber nicht überprüft), und es ist optional in den Datenbanken einiger anderer Anbieter, die eine Funktion verwenden, die oft als "Clustered-Indizes" oder "Index-organisierte Tabellen" bezeichnet wird. Diese Funktion wird derzeit nicht von PostgreSQL unterstützt (mindestens ab Version 9.3).

Das heißt, der PRIMARY KEY wird mit einem UNIQUE implementiert Index, und es gibt eine Reihenfolge für diesen Index. Es wird in aufsteigender Reihenfolge von der linken Spalte des Indexes (und damit dem Primärschlüssel) an sortiert, als wäre es ORDER BY col1 ASC, col2 ASC, col3 ASC; . Das gleiche gilt für jeden anderen b-Tree-Index (im Unterschied zu GiST oder GIN) in PostgreSQL, da sie mit b+trees implementiert werden.

Also in der Tabelle:

CREATE TABLE demo (
   a integer,
   b text, 
   PRIMARY KEY(a,b)
);

das System erstellt automatisch das Äquivalent von:

CREATE UNIQUE INDEX demo_pkey ON demo(a ASC, b ASC);

Dies wird Ihnen mitgeteilt, wenn Sie eine Tabelle erstellen, zB:

regress=>     CREATE TABLE demo (
regress(>        a integer,
regress(>        b text, 
regress(>        PRIMARY KEY(a,b)
regress(>     );
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "demo_pkey" for table "demo"
CREATE TABLE

Sie können diesen Index sehen, wenn Sie die Tabelle untersuchen:

regress=> \d demo
     Table "public.demo"
 Column |  Type   | Modifiers 
--------+---------+-----------
 a      | integer | not null
 b      | text    | not null
Indexes:
    "demo_pkey" PRIMARY KEY, btree (a, b)

Sie können CLUSTER auf diesem Index, um die Tabelle gemäß dem Primärschlüssel neu zu ordnen, aber es ist ein einmaliger Vorgang. Das System behält diese Reihenfolge nicht bei, wenn auf den Seiten aufgrund eines nicht standardmäßigen FILLFACTOR Platz frei ist Ich denke, es wird versuchen.

Eine Folge der inhärenten Reihenfolge des Index (aber nicht des Haufens) ist, dass es viel ist schneller zu suchen nach:

SELECT * FROM demo ORDER BY a, b;
SELECT * FROM demo ORDER BY a;

als:

SELECT * FROM demo ORDER BY a DESC, b;

und keiner von beiden kann den Primärschlüsselindex überhaupt verwenden, sie führen einen Seqscan durch, es sei denn, Sie haben einen Index auf b :

SELECT * FROM demo ORDER BY b, a;
SELECT * FROM demo ORDER BY b;

Dies liegt daran, dass PostgreSQL einen Index für (a,b) verwenden kann fast so schnell wie ein Index auf (a) allein. Es kann keinen Index auf (a,b) verwenden als wäre es ein Index auf (b) allein - nicht einmal langsam, es kann einfach nicht.

Wie für DESC Eintrag, für diesen einen Pg muss ein Rückwärts-Index-Scan durchgeführt werden, der langsamer ist als ein gewöhnlicher Vorwärts-Index-Scan. Wenn Sie viele Reverse-Index-Scans in EXPLAIN ANALYZE sehen und Sie sich die Leistungskosten des zusätzlichen Index leisten können, können Sie einen Index für das Feld in DESC erstellen bestellen.

Dies gilt für WHERE Klauseln, nicht nur ORDER BY . Sie können einen Index für (a,b) verwenden um nach WHERE a = 4 zu suchen oder WHERE a = 4 AND b = 3 aber nicht um nach WHERE b = 3 zu suchen allein.