CLUSTER — 根据一个索引聚集一个表
CLUSTER [ (option[, ...] ) ] [table_name[ USINGindex_name] ] whereoptioncan be one of: VERBOSE [boolean]
CLUSTER 指示 PostgreSQL 基于 index_name 所指定的索引来聚集 table_name 所指定的表。该索引必须已经定义在 table_name 上。
当一个表被聚集后,它会基于索引信息在物理上重新排序。聚集是一次性操作:当表随后被更新时,更改不会被聚集。也就是说,不会尝试按照索引顺序存储新插入或更新过的行。(如果愿意,可以通过再次发出该命令来周期性地重新聚集。此外,将表的 fillfactor 存储参数设置为小于 100% 也有助于在更新期间保持聚集顺序,因为在空间足够的情况下,更新过的行会保留在同一页上。)
当一个表被聚集后,PostgreSQL 会记住它是根据哪个索引聚集的。CLUSTER 形式会使用与之前相同的索引重新聚集该表。也可以使用 table_nameCLUSTER 或 SET WITHOUT CLUSTER 形式的 ALTER TABLE 来设置未来聚集操作所使用的索引,或者清除以前的设置。
CLUSTER 不带 table_name 时,会重新聚集当前数据库中调用用户对其拥有特权、且之前已被聚集过的所有表。这种形式的 CLUSTER 不能在事务块内执行。
在聚集一个表时,会在该表上获取一个 ACCESS EXCLUSIVE 锁。这会阻止任何其他数据库操作(读取和写入)对该表进行操作,直到 CLUSTER 完成。
table_name一个表的名字(可以用模式限定)。
index_name一个索引的名字。
VERBOSE 在每个表被聚集时以 INFO 级别打印进度报告。
boolean 指定所选选项应被打开还是关闭。可以写 TRUE、ON 或 1 来启用该选项,写 FALSE、OFF 或 0 来禁用它。boolean 值也可以省略,此时假定为 TRUE。
要聚集一个表,你必须拥有该表上的 MAINTAIN 特权。
在表中随机访问单个行的情况下,表中数据的实际顺序并不重要。但是,如果你对某些数据的访问多于其他数据,并且存在一个能把这些数据归拢到一起的索引,那么使用 CLUSTER 会使你受益。如果你从表中请求一个索引值的范围,或者请求一个有多个匹配行的单个索引值,CLUSTER 会有所帮助,因为一旦索引定位到第一个匹配行所在的表页,其余所有匹配行很可能已经在同一个表页上,这样就可以减少磁盘访问并加快查询速度。
CLUSTER 可以使用指定索引上的索引扫描,或者(如果该索引是 b-tree)先做顺序扫描再排序,来对表重新排序。它会基于规划器的代价参数和可用的统计信息,尝试选择更快的方法。
在 CLUSTER 运行期间,search_path 会被临时更改为 pg_catalog, pg_temp。
使用索引扫描时,会创建该表的一个临时副本,其中按索引顺序存放表数据。同时也会为该表上的每个索引创建临时副本。因此,你需要的磁盘空闲空间至少等于表大小加上各索引大小之和。
使用顺序扫描加排序时,还会创建一个临时排序文件,因此峰值临时空间需求最高可达表大小的两倍,再加上索引的大小。这种方法通常比索引扫描方法更快,但如果磁盘空间需求让人无法接受,可以通过将 enable_sort 临时设置为 off 来禁用这种选择。
建议在聚集之前把 maintenance_work_mem 设置为一个适当较大的值(但不要超过你能专用于 CLUSTER 操作的内存量)。
由于规划器会记录关于表顺序的统计信息,建议在新聚集的表上运行 ANALYZE。否则,规划器可能会做出糟糕的查询计划选择。
由于 CLUSTER 会记住用于聚集的索引,你可以第一次手动聚集想要的表,然后设置一个周期性维护脚本来执行不带任何参数的 CLUSTER,从而让所需的表被周期性地重新聚集。
每个运行 CLUSTER 的后端都会在 pg_stat_progress_cluster 视图中报告其进度。详情参见 Section 27.4.2。
聚集一个分区表会使用指定分区索引的对应分区来聚集它的每一个分区。在聚集分区表时,索引不能省略。对分区表执行 CLUSTER 不能在事务块内进行。
基于其索引 employees_ind 聚集表 employees:
CLUSTER employees USING employees_ind;
使用之前所用的相同索引聚集 employees 表:
CLUSTER employees;
聚集数据库中之前被聚集过的所有表:
CLUSTER;
SQL 标准中没有 CLUSTER 语句。
在 PostgreSQL 17 之前使用的是下面的语法,目前仍然支持:
CLUSTER [ VERBOSE ] [table_name[ USINGindex_name] ]
在 PostgreSQL 8.3 之前使用的是下面的语法,目前仍然支持:
CLUSTERindex_nameONtable_name