关于 postgres 中的聚集索引

Posted

技术标签:

【中文标题】关于 postgres 中的聚集索引【英文标题】:About clustered index in postgres 【发布时间】:2011-06-15 08:33:23 【问题描述】:

我正在使用 psql 访问 postgres 数据库。在查看表的元数据时,有什么方法可以查看表的索引是否为聚集索引?

听说表的 PRIMARY KEY 会自动关联聚集索引,是真的吗?

【问题讨论】:

PostgreSQL 没有聚集索引,但您为什么认为这很有趣?你有问题要解决吗? 没有特别的问题需要解决。刚刚学习 postgre :-) 如果不是这个问题,我会想为什么我的表没有自动碎片整理 我认为 Microsoft SQL 确实如此:主键自动与聚集索引相关联。但显然不适用于 PostgreSQL。 【参考方案1】:

请注意,PostgreSQL 使用术语“聚集索引”来使用与 SQL Server 模糊相似但又非常不同的东西。

如果一个特定的索引已经被指定为一个表的聚簇索引,那么 psql 的\d 命令将指示聚簇索引,例如,

Indexes:
    "timezone_description_pkey" PRIMARY KEY, btree (timezone) CLUSTER

默认情况下,PostgreSQL 不指定索引作为集群索引。即使如此指定,它也不会自动排列表数据以与聚簇索引相关:必须使用 CLUSTER 命令来重新组织表数据。

【讨论】:

更适合调用'reorganise table' 确切地说,Postgres 根本没有使用术语“聚集索引”。有“集群表”——在 CLUSTER 运行之后。【参考方案2】:

在 PostgreSQL 中,聚集属性保存在相应索引的元数据中,而不是关系本身。它是pg_index 目录中的indisclustered 属性。但是请注意,postgres 中的聚类关系是一次性操作:即使属性为真,对表的更新也不会保持数据的排序性质。迄今为止,数据聚类的自动维护仍然是一个流行的TODO项目。

clusteredintegrated 索引之间经常存在混淆,特别是因为流行的教科书使用了相互冲突的名称,而 postgres 和 SQL server 的手册中的术语又有所不同(仅举两个)。当我谈到集成索引(也称为主索引主索引)时,我指的是关系数据包含在索引的叶子,而不是 externalsecondary 索引,其中叶子包含指向表记录的索引条目。前一种类型必然总是聚集的。不幸的是 postgres 只支持后一种类型。无论如何,集成(主)索引始终是聚集的这一事实可能已经引起了“表的 PRIMARY KEY 自动与聚集索引相关联”的信念。这两种说法听起来相似,但又有所不同。

【讨论】:

我相信 SQL Server 也会让主键默认使用聚集索引,除非你另有说明,对吧?这可能会导致混淆或导致假设两者必然意味着相同的事情。 是的,根据msdn.microsoft.com/en-us/library/ms174979.aspx“PRIMARY KEY 约束默认为 CLUSTERED,UNIQUE 约束默认为 NONCLUSTERED。”【参考方案3】:

有什么方法可以查看表的索引是否为聚集索引

PostgreSQL 没有聚集索引,因此您将无法看到它们。

听说表的 PRIMARY KEY 会自动关联聚集索引,是真的吗?

不,那不是真的(见上文)

您可以沿着索引手动聚集表,但这不会自动维护(例如,使用 SQL Server 的聚集索引)。

更多详情请参见手册中CLUSTER命令的说明。

【讨论】:

那我可以用 \d 来判断一个表是否是沿着索引聚集的吗? 如果我正确阅读手册,\dS+ 应该这样做。只需查看帮助并使用选项即可。【参考方案4】:

PostgreSQL 没有像 Microsoft SQL Server 那样直接实现 CLUSTER 索引。

Reference Taken from this Blog:

在 PostgreSQL 中,我们有一个类似于集群索引的 CLUSTER 命令。

创建表主键或任何其他索引后,您可以通过指定该索引名称来执行 CLUSTER 命令以实现表数据的物理顺序。

当一个表被聚集时,它会根据索引信息在物理上重新排序。集群是一次性操作:当表随后更新时,更改不会集群。也就是说,不会尝试根据索引顺序存储新的或更新的行。

集群语法:

第一次必须使用索引名称执行 CLUSTER。

CLUSTER table_name USING index_name;

对表进行聚类:

一旦你用索引执行了 CLUSTER,下次你应该只执行 CLUSTER TABLE,因为它知道哪个索引已经定义为 CLUSTER。

CLUSTER table_name;

【讨论】:

【参考方案5】:

集群索引

集群索引意味着告诉数据库在磁盘上存储实际上彼此接近的接近值。它们可以唯一标识 SQL 表中的行。每个表都可以只有一个聚集索引。一个聚集索引可以覆盖多个列。默认情况下,具有主键的列已经具有聚集索引。

dictionary

字典本身就是一个带有聚集索引的表。因为所有数据都是按字母顺序物理存储的。


非集群索引

非聚集索引就像一本书的简单索引。它们仅用于快速检索数据。不确定是否有唯一数据。非聚集索引包含非聚集索引键及其对应的数据位置指针。例如,一本书的内容索引包含一个主题或章节的关键字以及该主题或章节的页面位置。

book content index

一本书的内容表包含内容名称及其页面位置。不确定数据是否唯一。因为同一段落或文本行或单词可以多次放置。


PostgreSQL 索引

PostgreSQL 自动为表的PRIMARY KEY 和每个UNIQUE 约束创建索引。在 PostgreSQL 终端中登录数据库并输入 \d table_name。所有存储的索引都将被可视化。如果有聚集索引,那么它也会被识别出来。

创建表格

CREATE TABLE IF NOT EXISTS profile(
    uid serial NOT NULL UNIQUE PRIMARY KEY,
    username varchar(30) NOT NULL UNIQUE,
    phone varchar(11) NOT NULL UNIQUE,
    age smallint CHECK(age>12),
    address text NULL
);

3 索引将自动创建。所有这些索引都是非聚集的

"profile_pkey" PRIMARY KEY, btree (uid)
"profile_phone_key" UNIQUE CONSTRAINT, btree (phone)
"profile_username_key" UNIQUE CONSTRAINT, btree (username)

使用 uid 和用户名创建我们自己的索引

CREATE INDEX profile_index ON profile(uid, username);

这实际上创建了一个非聚集索引。要使其集群化,请运行下一部分。

将非聚集索引转换为聚集索引

ALTER TABLE profile CLUSTER ON profile_index;

使用\d profile 检查表格。会是这样的:

                                     Table "public.profile"
  Column  |         Type          | Collation | Nullable |               Default
----------+-----------------------+-----------+----------+--------------------------------------
 uid      | integer               |           | not null | nextval('profile_uid_seq'::regclass)
 username | character varying(30) |           | not null |
 phone    | character varying(11) |           | not null |
 age      | smallint              |           |          |
 address  | text                  |           |          |
Indexes:
    "profile_pkey" PRIMARY KEY, btree (uid)
    "profile_phone_key" UNIQUE CONSTRAINT, btree (phone)
    "profile_username_key" UNIQUE CONSTRAINT, btree (username)
    "profile_index" btree (uid, username) CLUSTER
Check constraints:
    "profile_age_check" CHECK (age > 12)

请注意,profile_index 现在是“CLUSTER”

现在,重新对表进行集群,以便表可以遵循集群索引角色

CLUSTER profile;

【讨论】:

这似乎混淆了 PostgreSQL 和 SQL Server 中集群的不同概念。 空间方面,非聚集索引占用的空间与表本身一样多。 CLUSTER 命令只是一个元数据,不会像 sqlserver 中那样节省空间。【参考方案6】:

如果您想使用 SQL 了解给定表是否为 CLUSTERed,您可以使用以下查询来显示正在使用的索引(在 Postgres 版本 9.5 和 9.6 中测试):

SELECT
  i.relname AS index_for_cluster
FROM
  pg_index AS idx
JOIN
  pg_class AS i
ON
  i.oid = idx.indexrelid
WHERE
  idx.indisclustered
  AND idx.indrelid::regclass = 'your_table_name'::regclass;

【讨论】:

@DanielL.VanDenBosch,错误是什么?我刚刚重新检查了它对我有用(并在我的回答中澄清了 postgres 版本)。 很棒的脚本,我可以用它来检查我的主键是否是集群的。这应该被标记为正确的答案。

以上是关于关于 postgres 中的聚集索引的主要内容,如果未能解决你的问题,请参考以下文章

聚集索引非聚集索引主键

数据库中的聚集索引非聚集索引优化索引

主键上的非聚集索引?

聚集索引和非聚集索引之间的区别 [重复]

04.索引-聚集索引 堆表聚集表聚集索引结构

聚集索引和非聚集索引