Câu hỏi này tạo ra giả định sai lầm rằng khóa chính áp đặt một thứ tự bảng nào cả. Nó không. Các bảng PostgreSQL không có thứ tự xác định, có hoặc không có khóa chính; chúng là một "đống" các hàng được sắp xếp trong các khối trang. Đặt hàng được áp dụng bằng cách sử dụng ORDER BY
mệnh đề truy vấn khi muốn.
Bạn có thể nghĩ rằng các bảng PostgreSQL được lưu trữ dưới dạng bảng hướng chỉ mục được lưu trữ trên đĩa theo thứ tự khóa chính, nhưng đó không phải là cách Pg hoạt động. Tôi nghĩ rằng InnoDB lưu trữ các bảng được tổ chức theo khóa chính (nhưng chưa được kiểm tra) và nó là tùy chọn trong cơ sở dữ liệu của một số nhà cung cấp khác bằng cách sử dụng một tính năng thường được gọi là "chỉ mục nhóm" hoặc "bảng được tổ chức theo chỉ mục". Tính năng này hiện không được PostgreSQL hỗ trợ (ít nhất là 9.3).
Điều đó nói lên rằng, PRIMARY KEY
được triển khai bằng UNIQUE
chỉ mục, và có một thứ tự cho chỉ mục đó. Nó được sắp xếp theo thứ tự tăng dần từ cột bên trái của chỉ mục (và do đó là khóa chính) trở đi, như thể nó là ORDER BY col1 ASC, col2 ASC, col3 ASC;
. Điều này cũng đúng với bất kỳ chỉ mục b-tree nào khác (khác với GiST hoặc GIN) trong PostgreSQL, vì chúng được triển khai bằng cách sử dụng b + tree.
Vì vậy, trong bảng:
CREATE TABLE demo (
a integer,
b text,
PRIMARY KEY(a,b)
);
hệ thống sẽ tự động tạo tương đương với:
CREATE UNIQUE INDEX demo_pkey ON demo(a ASC, b ASC);
Điều này được báo cáo cho bạn khi bạn tạo một bảng, ví dụ:
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
Bạn có thể thấy chỉ mục này khi kiểm tra bảng:
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)
Bạn có thể CLUSTER
trên chỉ mục này để sắp xếp lại bảng theo khóa chính, nhưng đó là hoạt động một lần. Hệ thống sẽ không duy trì thứ tự đó - mặc dù nếu có dung lượng trống trong các trang do FILLFACTOR
không mặc định Tôi nghĩ nó sẽ cố gắng.
Một hệ quả của thứ tự vốn có của chỉ mục (nhưng không phải là đống) là nó nhiều nhanh hơn để tìm kiếm:
SELECT * FROM demo ORDER BY a, b;
SELECT * FROM demo ORDER BY a;
hơn:
SELECT * FROM demo ORDER BY a DESC, b;
và cả hai thứ này đều không thể sử dụng chỉ mục khóa chính, chúng sẽ quét seqscan trừ khi bạn có chỉ mục trên b
:
SELECT * FROM demo ORDER BY b, a;
SELECT * FROM demo ORDER BY b;
Điều này là do PostgreSQL có thể sử dụng một chỉ mục trên (a,b)
nhanh như một chỉ mục trên (a)
một mình. Nó không thể sử dụng chỉ mục trên (a,b)
như thể nó là một chỉ mục trên (b)
một mình - thậm chí không từ từ, nó chỉ là không thể.
Đối với DESC
mục nhập, đối với Pg đó phải thực hiện quét chỉ mục ngược, tốc độ này chậm hơn so với quét chỉ mục chuyển tiếp thông thường. Nếu bạn thấy nhiều lần quét chỉ mục ngược trong EXPLAIN ANALYZE
và bạn có thể chi trả chi phí hiệu suất của chỉ mục bổ sung, bạn có thể tạo chỉ mục trên trường trong DESC
đặt hàng.
Điều này đúng với WHERE
các mệnh đề, không chỉ ORDER BY
. Bạn có thể sử dụng chỉ mục trên (a,b)
để tìm kiếm WHERE a = 4
hoặc WHERE a = 4 AND b = 3
nhưng không để tìm kiếm WHERE b = 3
một mình.