To pytanie wprowadza błędne założenie, że klucz podstawowy w ogóle narzuca kolejność tabel. Nie. Tabele PostgreSQL nie mają zdefiniowanej kolejności, z kluczem podstawowym lub bez; są „stosem” wierszy ułożonych w bloki stron. Zamówienie jest narzucane za pomocą ORDER BY
klauzula zapytań w razie potrzeby.
Możesz myśleć, że tabele PostgreSQL są przechowywane jako tabele zorientowane na indeks, które są przechowywane na dysku w kolejności klucza podstawowego, ale tak nie działa Pg. Myślę, że InnoDB przechowuje tabele zorganizowane według klucza podstawowego (ale nie zostały sprawdzone) i jest opcjonalne w bazach danych niektórych innych dostawców przy użyciu funkcji często nazywanej „indeksy klastrowe” lub „tabele zorganizowane według indeksów”. Ta funkcja nie jest obecnie obsługiwana przez PostgreSQL (przynajmniej od wersji 9.3).
To powiedziawszy, PRIMARY KEY
jest zaimplementowany przy użyciu UNIQUE
indeks i istnieje kolejność tego indeksu. Jest sortowany w porządku rosnącym od lewej kolumny indeksu (a zatem od klucza podstawowego) dalej, tak jakby był ORDER BY col1 ASC, col2 ASC, col3 ASC;
. To samo dotyczy każdego innego indeksu b-drzewa (w odróżnieniu od GiST lub GIN) w PostgreSQL, ponieważ są one zaimplementowane przy użyciu b+drzewa.
Więc w tabeli:
CREATE TABLE demo (
a integer,
b text,
PRIMARY KEY(a,b)
);
system automatycznie utworzy odpowiednik:
CREATE UNIQUE INDEX demo_pkey ON demo(a ASC, b ASC);
Jest to zgłaszane podczas tworzenia tabeli, np.:
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
Możesz zobaczyć ten indeks podczas sprawdzania tabeli:
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)
Możesz CLUSTER
na tym indeksie, aby zmienić kolejność tabeli zgodnie z kluczem podstawowym, ale jest to jednorazowa operacja. System nie utrzyma tej kolejności - chociaż jeśli na stronach jest wolne miejsce z powodu niedomyślnego FILLFACTOR
Myślę, że spróbuje.
Jedną z konsekwencji nieodłącznej kolejności indeksu (ale nie sterty) jest to, że jest dużo szybsze wyszukiwanie:
SELECT * FROM demo ORDER BY a, b;
SELECT * FROM demo ORDER BY a;
niż:
SELECT * FROM demo ORDER BY a DESC, b;
i żaden z nich nie może w ogóle używać indeksu klucza podstawowego, wykonają seqscan, chyba że masz indeks na b
:
SELECT * FROM demo ORDER BY b, a;
SELECT * FROM demo ORDER BY b;
Dzieje się tak, ponieważ PostgreSQL może używać indeksu w (a,b)
prawie tak szybko, jak indeks na (a)
sam. Nie może używać indeksu w (a,b)
jakby to był indeks na (b)
sam - nawet nie wolno, po prostu nie może.
Co do DESC
wpis, dla tego jednego Pg musi wykonać skanowanie indeksu wstecznego, które jest wolniejsze niż zwykłe skanowanie indeksu w przód. Jeśli widzisz wiele skanów odwrotnego indeksu w EXPLAIN ANALYZE
i możesz sobie pozwolić na koszt wydajności dodatkowego indeksu, możesz utworzyć indeks w polu w DESC
zamówienie.
Dotyczy to WHERE
klauzul, nie tylko ORDER BY
. Możesz użyć indeksu na (a,b)
aby wyszukać WHERE a = 4
lub WHERE a = 4 AND b = 3
ale nie aby wyszukać WHERE b = 3
sam.