19

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

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

此外,在 PostgreSQL 的情况下,主键是否会自动编制索引?

4

1 回答 1

54

这个问题做出了错误的假设,即主键根本就强加了表顺序。它没有。PostgreSQL 表没有定义的顺序,有或没有主键;它们是按页块排列的行“堆”。ORDER BY需要时使用查询子句进行排序。

您可能会认为 PostgreSQL 表被存储为以主键顺序存储在磁盘上的面向索引的表,但这不是 Pg 的工作方式。我认为 InnoDB 存储由主键组织的表(但尚未检查),并且在其他一些供应商的数据库中使用通常称为“聚集索引”或“索引组织表”的功能是可选的。PostgreSQL 目前不支持此功能(至少从 9.3 开始)。

也就是说,它PRIMARY KEY是使用UNIQUE索引实现的,并且该索引有一个排序。它从索引的左列(因此是主键)开始按升序排序,就好像它是ORDER BY col1 ASC, col2 ASC, col3 ASC;. PostgreSQL 中的任何其他 b-tree(与 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;

并且这些都不能使用主键索引,除非你有一个索引,否则它们会执行 seqscan b

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

这是因为 PostgreSQL 使用索引几乎和单独使用索引(a,b)一样快。(a)它不能像单独使用索引(a,b)一样使用索引(b)- 甚至不能缓慢,它就是不能。

至于DESCentry,对于那个Pg,必须做一个反向索引扫描,比普通的正向索引扫描要慢。如果您看到大量反向索引扫描,EXPLAIN ANALYZE并且您可以负担额外索引的性能成本,则可以按DESC顺序在字段上创建索引。

这适用于WHERE从句,而不仅仅是ORDER BY. 您可以使用索引(a,b)来搜索WHERE a = 4或单独搜索,WHERE a = 4 AND b = 3不能单独搜索WHERE b = 3

于 2012-11-02T07:28:16.907 回答