2012-11-02 2 views

Antwort

36

Diese Frage führt zu der fehlgeleiteten Annahme, dass der Primärschlüssel überhaupt eine Tabellenreihenfolge erzwingt. Es 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 unter Verwendung der ORDER BY Klausel von Abfragen auferlegt, falls gewünscht.

Sie könnten denken, dass PostgreSQL-Tabellen als indexorientierte Tabellen gespeichert sind, die auf der Festplatte in der Reihenfolge der Primärschlüssel gespeichert sind, aber so funktioniert Pg nicht. Ich denke, InnoDB speichert Tabellen, die nach dem Primärschlüssel organisiert sind (aber nicht geprüft wurden), und ist in den Datenbanken anderer Hersteller optional, wenn man eine Funktion verwendet, die oft "Clustered-Indizes" oder "Index-organisierte Tabellen" genannt wird. Diese Funktion wird derzeit von PostgreSQL nicht unterstützt (mindestens ab Version 9.3).

Das heißt, die PRIMARY KEY ist mit einem UNIQUE Index implementiert, und es gibt eine Reihenfolge zu diesem Index. Es ist in aufsteigender Reihenfolge von der linken Spalte des Indexes (und daher des Primärschlüssels) aufwärts sortiert, als ob es ORDER BY col1 ASC, col2 ASC, col3 ASC; wäre. Das Gleiche gilt für alle anderen b-tree-Indizes (im Unterschied zu GiST oder GIN) in PostgreSQL, da sie unter Verwendung von b+trees implementiert werden.

So in der Tabelle:

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

das System das Äquivalent automatisch erstellen:

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

Dies Ihnen wird angezeigt, 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 bei der Untersuchung der Tabelle sehen:

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 für diesen Index verwenden, um die Tabelle nach dem Primärschlüssel neu zu ordnen, aber es handelt sich um eine einmalige Operation. Das System wird diese Reihenfolge nicht beibehalten - obwohl es Platz frei auf den Seiten aufgrund eines nicht standardmäßigen gibt, denke ich, dass es versuchen wird.

Eine Folge der inhärenten Ordnung des Index (aber nicht der Heap) ist, dass es schneller suchen viel für:

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 diese können den Primärschlüsselindex überhaupt verwenden, sie führen einen Seqscan durch, es sei denn, Sie haben einen Index für b:

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

Dies ist weil PostgreSQL kann einen Index auf (a,b) fast so schnell wie ein Index auf (a) allein verwenden.Es kann nicht einen Index auf (a,b) als ob es ein Index auf allein wäre - nicht einmal langsam, es kann einfach nicht.

Wie für den Eintrag DESC, für diesen muss Pg einen umgekehrten Index-Scan durchführen, der langsamer ist als ein gewöhnlicher Vorwärtsindex-Scan. Wenn Sie in EXPLAIN ANALYZE viele Reverse-Index-Scans sehen und sich die Performance-Kosten des Extra-Index leisten können, können Sie einen Index für das Feld in der Reihenfolge DESC erstellen.

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

+0

Also sollte ich davon ausgehen, dass Nachschlagewerke auf der Grundlage der am weitesten links Spalte am schnellsten im Vergleich zu den Spalten rechts sein werden (die Spalten, die ich spreche sind alle Spalten, die den Primärschlüssel bilden)? –

+1

@AbhishekJain Richtig; Die Verwendung der äußersten linken Spalte des PK (oder von Suchvorgängen, die beide Spalten verwenden) wird den Index verwenden, während die Verwendung der ganz rechten Spalte von nur PK * den Index überhaupt nicht verwenden kann. Es kann hilfreich sein, einen zweiten Index nur in der Spalte ganz rechts zu erstellen, wenn Sie sehr oft nachschlagen müssen, oder die Reihenfolge des Primärschlüssels umzukehren, wenn Sie die andere Spalte nicht alleine suchen müssen. –

+2

@AbhishekJain Gern geschehen. Ich rate Ihnen dringend, sich mit dem Befehl "EXPLAIN ANALYZE" und mit der Shell "psql" vertraut zu machen. Beide werden Ihnen helfen zu verstehen, wie PostgreSQL besser funktioniert, analysieren, wie Abfragen ausgeführt werden, verschiedene Indizierungsstrategien testen usw. http://explain.depesz.com/ kann nützlich sein, wenn Sie versuchen, große und komplexe Abfragepläne zu verstehen. –