在PostgreSQL中,当多个列的组合被指定为PRIMARY KEY
时,记录是如何排序的?
这是假设PostgreSQL按主键的顺序对记录进行排序。是吗?
另外,在PostgreSQL的情况下,主键是否自动编入索引?
答案 0 :(得分:42)
这个问题误导了主键强加了一个表顺序。它没有。 PostgreSQL表没有定义的顺序,有或没有主键;它们是页面块中排列的行的“堆”。在需要时,使用查询的ORDER BY
子句强制进行排序。
您可能认为PostgreSQL表存储为面向索引的表,这些表以主键顺序存储在磁盘上,但这不是Pg的工作方式。我认为InnoDB存储由主键组织的表(但尚未检查),并且在一些其他供应商的数据库中使用通常称为“聚簇索引”或“索引组织表”的功能是可选的。 PostgreSQL目前不支持此功能(至少从9.3开始)。
也就是说,PRIMARY KEY
是使用UNIQUE
索引实现的,并且对该索引有一个排序。它从索引的左列(以及主键)开始按升序排序,就好像它是ORDER BY col1 ASC, col2 ASC, col3 ASC;
一样。 PostgreSQL中的任何其他b树(与GiST或GIN不同)索引也是如此,因为它们是使用b+trees实现的。
所以在表格中:
CREATE TABLE demo (
a integer,
b text,
PRIMARY KEY(a,b)
);
系统将自动创建相当于:
CREATE UNIQUE INDEX demo_pkey ON demo(a ASC, b ASC);
创建表时会向您报告,例如:
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
检查表时可以看到此索引:
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)
您可以在此索引上CLUSTER
根据主键重新排序表,但这是一次性操作。系统不会保持这种顺序 - 但是如果由于非默认FILLFACTOR
而页面中有空间,我认为它会尝试。
索引(但不是堆)的固有排序的一个结果是, 更快地搜索:
SELECT * FROM demo ORDER BY a, b;
SELECT * FROM demo ORDER BY a;
比:
SELECT * FROM demo ORDER BY a DESC, b;
并且它们都不能使用主键索引,除非您在b
上有索引,否则它们将执行seqscan:
SELECT * FROM demo ORDER BY b, a;
SELECT * FROM demo ORDER BY b;
这是因为PostgreSQL可以使用(a,b)
上的索引几乎与(a)
上的索引一样快。它不能在(a,b)
上使用索引,就好像它只是(b)
上的索引一样 - 不是很慢,它不能。
对于DESC
条目,对于那个Pg必须进行反向索引扫描,这比普通的正向索引扫描慢。如果您在EXPLAIN ANALYZE
中看到许多反向索引扫描,并且您可以承担额外索引的性能成本,则可以按DESC
顺序在字段上创建索引。
这适用于WHERE
条款,而不仅仅是ORDER BY
。您可以使用(a,b)
上的索引搜索WHERE a = 4
或WHERE a = 4 AND b = 3
,但不以单独搜索WHERE b = 3
。