CLUSTER
CLUSTER — 按照一个索引对表进行聚簇
大纲
CLUSTER [VERBOSE]table_name[ USINGindex_name] CLUSTER [VERBOSE]
描述
CLUSTER 指示 PostgreSQL
按照 index_name
指定的索引,对 table_name
指定的表进行聚簇。该索引必须已经定义在
table_name 上。
当一个表被聚簇时,它会根据索引信息在物理上重新排序。聚簇是一次性操作:之后如果表再被更新,这些更改不会再次被聚簇。也就是说,系统不会试图按照索引顺序存储新行或更新后的行。(如果需要,可以定期再次执行该命令来重新聚簇。此外,将表的 FILLFACTOR
存储参数设置为小于 100%,有助于在更新期间保持聚簇顺序,因为如果页面上有足够空间,更新后的行会保留在同一页面中。)
当一个表被聚簇时,PostgreSQL
会记住该表是按哪个索引聚簇的。形式
CLUSTER
会使用与之前相同的索引对表重新聚簇。你也可以使用ALTER TABLE的
table_nameCLUSTER 或 SET WITHOUT CLUSTER
形式,设置未来聚簇操作要使用的索引,或者清除任何先前的设置。
不带任何参数的 CLUSTER 会对当前数据库中所有此前已聚簇且属于调用用户的表重新执行聚簇;如果由超级用户调用,则会对所有此前已聚簇的表重新执行聚簇。这种形式的 CLUSTER 不能在事务块内执行。
当对一个表执行聚簇时,会在该表上获取 ACCESS
EXCLUSIVE 锁。这会阻止任何其他数据库操作(包括读和写)在 CLUSTER 完成前访问该表。
参数
table_name表的名称(可能是模式限定的)。
index_name索引的名称。
VERBOSE在每个表被聚簇时打印进度报告。
注解
当你在表中随机访问单行时,数据在表中的实际顺序并不重要。但是,如果访问某些数据比其他数据更频繁,并且存在将这些数据放在一起的索引,使用CLUSTER就会有益。如果要从表中获取一段索引值范围,或者获取有多行匹配的单个索引值,CLUSTER会有帮助,因为一旦索引确定第一个匹配行所在的表页,其他匹配行很可能已在同一个表页中,从而减少磁盘访问并加快查询。
使用索引扫描时,会创建一个表的临时副本,其中表数据按索引顺序排列。还会为表上的每个索引创建临时副本。因此,所需的磁盘空闲空间至少应等于表大小与索引大小之和。
由于CLUSTER会记住聚簇信息,你可以第一次手工聚簇想要聚簇的表,然后设置一个类似于VACUUM的定时事件,让这些表被周期性地重新聚簇。
因为规划器会记录有关表中数据顺序的统计信息,建议在新近聚簇过的表上运行ANALYZE。否则,规划器可能会选择很差的查询计划。
还有另一种聚簇数据的方法。CLUSTER命令通过使用你指定的索引扫描原始表来对它重新排序。这对于大型表可能很慢,因为行是按索引顺序从表中取得的,而如果表是无序的,条目就散布在随机页面中,因此每移动一行都要检索一个磁盘页。(PostgreSQL有缓存,但一个大表的绝大部分放不进缓存。)另一种聚簇表的方法是使用:
CREATE TABLEnewtableAS SELECT * FROMtableORDER BYcolumnlist;
它使用PostgreSQL的排序代码产生想要的顺序;对于无序数据,这通常比索引扫描快得多。然后你删除旧表,使用ALTER TABLE ... RENAME把newtable改名为旧表的名字,并重建该表的索引。这种方法的最大缺点是它不保留 OID、约束、外键关系、被授予的权限以及表的其他附属属性—所有这些项都必须手工重建。另一个缺点是这种方式需要一个与表本身大小大致相同的排序临时文件,因此峰值磁盘用量约为表大小的三倍,而不是两倍。
示例
按照索引 employees_ind 对表
employees 进行聚簇:
CLUSTER employees USING employees_ind;
使用之前用过的同一个索引对 employees 表进行聚簇:
CLUSTER employees;
对数据库中此前已聚簇过的所有表执行聚簇:
CLUSTER;
兼容性
SQL 标准中没有 CLUSTER 语句。
语法
CLUSTERindex_nameONtable_name
也受支持,以兼容 8.3 之前的 PostgreSQL 版本。