PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Qual è l'ordine dei record in una tabella con una chiave primaria composita

Questa domanda fa il presupposto fuorviante che la chiave primaria imponga un ordine di tabella. Non è così. Le tabelle PostgreSQL non hanno un ordine definito, con o senza una chiave primaria; sono un "mucchio" di righe disposte in blocchi di pagina. L'ordine viene imposto utilizzando il ORDER BY clausola di query quando lo si desidera.

Potresti pensare che le tabelle PostgreSQL siano archiviate come tabelle orientate all'indice che sono archiviate su disco nell'ordine della chiave primaria, ma non è così che funziona Pg. Penso che InnoDB memorizzi le tabelle organizzate in base alla chiave primaria (ma non l'ho verificato) ed è facoltativo nei database di altri fornitori che utilizzano una funzionalità spesso chiamata "indici cluster" o "tabelle organizzate per indici". Questa funzionalità non è attualmente supportata da PostgreSQL (almeno a partire dalla 9.3).

Detto questo, la PRIMARY KEY è implementato utilizzando un UNIQUE index, e c'è un ordinamento per quell'indice. Viene ordinato in ordine crescente dalla colonna di sinistra dell'indice (e quindi la chiave primaria) in poi, come se fosse ORDER BY col1 ASC, col2 ASC, col3 ASC; . Lo stesso vale per qualsiasi altro indice b-tree (distinto da GiST o GIN) in PostgreSQL, poiché sono implementati utilizzando b+trees.

Quindi nella tabella:

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

il sistema creerà automaticamente l'equivalente di:

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

Questo ti viene segnalato quando crei una tabella, ad esempio:

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

Puoi vedere questo indice quando esamini la tabella:

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)

Puoi CLUSTER su questo indice per riordinare la tabella in base alla chiave primaria, ma è un'operazione una tantum. Il sistema non manterrà quell'ordine, anche se c'è spazio libero nelle pagine a causa di un FILLFACTOR non predefinito Penso che ci proverà.

Una conseguenza dell'ordinamento intrinseco dell'indice (ma non dell'heap) è che è molto più veloce da cercare:

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

di:

SELECT * FROM demo ORDER BY a DESC, b;

e nessuno di questi può utilizzare affatto l'indice della chiave primaria, eseguiranno un seqscan a meno che tu non abbia un indice su b :

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

Questo perché PostgreSQL può usare un indice su (a,b) veloce quasi quanto un indice su (a) solo. Non può utilizzare un indice su (a,b) come se fosse un indice su (b) da solo - nemmeno lentamente, semplicemente non può.

Per quanto riguarda il DESC voce, per quello Pg deve eseguire una scansione dell'indice inversa, che è più lenta di una normale scansione dell'indice in avanti. Se vedi molte scansioni dell'indice inverso in EXPLAIN ANALYZE e puoi permetterti il ​​costo delle prestazioni dell'indice extra puoi creare un indice sul campo in DESC ordine.

Questo vale per WHERE clausole, non solo ORDER BY . Puoi usare un indice su (a,b) per cercare WHERE a = 4 oppure WHERE a = 4 AND b = 3 ma non per cercare WHERE b = 3 solo.