具有复合主键的表中的记录顺序是什么

时间:2012-11-02 06:58:26

标签: postgresql sorting primary-key

在PostgreSQL中,当多个列的组合被指定为PRIMARY KEY时,记录是如何排序的?

这是假设PostgreSQL按主键的顺序对记录进行排序。是吗?

另外,在PostgreSQL的情况下,主键是否自动编入索引?

1 个答案:

答案 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 = 4WHERE a = 4 AND b = 3,但以单独搜索WHERE b = 3