【问题标题】:What is the order of records in a table with a composite primary key具有复合主键的表中记录的顺序是什么
【发布时间】:2012-11-02 06:58:26
【问题描述】:

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

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

另外,如果是 PostgreSQL,主键会自动索引吗?

【问题讨论】:

    标签: postgresql sorting primary-key


    【解决方案1】:

    这个问题做出了错误的假设,即主键完全强制了表顺序。它没有。 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;
    

    而且它们都不能使用主键索引,除非你在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

    【讨论】:

    • 那么,我应该假设基于最左边的列的查找比右边的列最快(我所说的列都是构成主键的列)?
    • @AbhishekJain 正确;使用 PK 的最左侧列(或使用两列的查找)将使用索引,而使用 PK only 的最右侧列将根本无法使用索引。如果您需要在最右边的列上创建第二个索引,或者如果您不需要单独查找另一列,则反转主键的顺序会很有帮助。
    • @AbhishekJain 不客气。我强烈建议您熟悉EXPLAIN ANALYZE 命令和psql 命令shell。两者都将帮助您了解 PostgreSQL 如何更好地工作、分析查询是如何执行的、测试不同的索引策略等。explain.depesz.com 在尝试理解大而复杂的查询计划时也很有用。
    猜你喜欢
    • 2019-10-13
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 2023-03-27
    • 1970-01-01
    • 2015-04-10
    相关资源
    最近更新 更多