CLUSTER — cluster a table according to an index
根据索引对表进行聚类
cluster指示postgresql根据index_name指定的索引对table_name指定的表进行集群。表上必须已经有索引。
当表被cluster时,它将根据索引信息进行物理重新排序。cluster是一次性操作:当表随后被更新时,更新不会被cluster。也就是说,不尝试根据新行或更新行的索引顺序存储新行或更新行。如果愿意,可以通过再次发出命令来定期重新调整。此外,将表的填满因子存储参数设置为小于100%有助于在更新期间保留群集顺序,因为如果有足够的空间,更新的行将保留在同一页上。)
当一个表被cluster 时,PostgreSQL会记住它被cluster 的索引。表单cluster table_name使用与以前相同的索引重新排序表。您还可以使用 cluster 或set without cluster form of alter table来设置将来cluster 操作要使用的索引,或者清除任何以前的设置。
不带任何参数的CLUSTER将重新对调用用户拥有的当前数据库中以前的所有聚集表进行排序,或者对超级用户调用的所有此类表进行排序。这种形式的集群不能在事务块内执行。
当一个表被cluster 时,它会获得一个访问排它锁。这将防止在集群完成之前对表进行任何其他数据库操作(读和写)。
执行参数:
table_name: 表名
index_name: 索引名。
berbose: 在每个表都聚集时打印进度报告。
在随机访问表中的单行的情况下,表中数据的实际顺序并不重要。但是,如果倾向于比其他人更多地访问一些数据,并且有一个索引将这些数据分组在一起,那么将从使用cluster中获益。如果从一个表中请求一个索引值范围,或者一个索引值有多个匹配的行,那么cluster将有所帮助,因为一旦索引为第一个匹配的行标识了表页,那么所有其他匹配的行可能已经在同一个表页上,因此可以保存磁盘访问并加快查询速度。
cluster 可以使用对指定索引的索引扫描,或者(如果索引是B树)顺序扫描,然后进行排序,对表进行重新排序。它将根据计划成本参数和可用的统计信息,尝试选择更快的方法。
使用索引扫描时,将创建一个临时表副本,其中包含按索引顺序排列的表数据。还将创建表上每个索引的临时副本。因此,您需要磁盘上的可用空间至少等于表大小和索引大小之和。
当使用顺序扫描和排序时,也会创建一个临时排序文件,以便峰值临时空间需求是表大小的两倍,加上索引大小。此方法通常比索引扫描方法快,但如果磁盘空间要求不可容忍,则可以通过暂时将“enable_sort”设置为“off”来禁用此选项。
建议在cluster 之前将 maintenance_work_mem 设置为一个相当大的值(但不超过您可以专门用于集群操作的RAM数量)。
因为计划器记录有关表顺序的统计信息,所以建议对新cluster 的表运行分析。否则,计划者可能会对查询计划做出错误的选择。
因为cluster 记住了哪些索引是cluster 的,所以可以对第一次需要手动cluster 的表进行cluster ,然后设置一个周期性维护脚本,在不使用任何参数的情况下执行集群,以便周期性地重新集群所需的表。
===========================================================================================
-- 实验环境:CentOS 7 + PG 11.1
-- 说明:实验SQL是根据 digoal 的实验,自己亲手做的。感谢德哥!!!
-- 创建实验表,索引
create table test (id int, val numeric);
create index on test(id);
create index on test(val);
-- 插入实验数据
insert into test select generate_series(1,10000000),random();
-- 表信息
\d test
Table "public.test"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
id | integer | | |
val | numeric | | |
Indexes:
"test_id_idx" btree (id)
"test_val_idx" btree (val)
-- 表文件
select pg_relation_filepath('test'::regclass);
pg_relation_filepath
----------------------
base/16385/64278
(1 row)
-- 索引文件
select pg_relation_filepath('test_id_idx'::regclass);
pg_relation_filepath
----------------------
base/16385/64280
(1 row)
-- 索引文件
select pg_relation_filepath('test_val_idx'::regclass);
pg_relation_filepath
----------------------
base/16385/64281
(1 row)
-- 查看列的离散程度,值越接近0,表示越离散,越接近1,表示存储比较有顺序
-- 说明目前表是根据 id 有序存储的。
select correlation from pg_stats where tablename='test' and attname='id';
correlation
-------------
1
select correlation from pg_stats where tablename='test' and attname='val';
correlation
-------------
0.00781794
(1 row)
-- 收缩表,分析表,收集统计信息。
vacuum analyze test;
-- 最小的ID的存储位置
select ctid,id,val from test where id=(select min(id) from test);
ctid | id | val
-------+----+-------------------
(0,1) | 1 | 0.419486843980849
(1 row)
-- 最小的 VAL 的存储位置
select ctid,id,val from test where val=(select min(val) from test);
ctid | id | val
------------+--------+------------------------
(4361,127) | 806540 | 0.00000218348577618599
(1 row)
-- 根据 val 列上的索引。做cluster。
cluster test USING test_val_idx;
-- 查看最小 id 的存储
select ctid,id,val from test where id=(select min(id) from test);
ctid | id | val
----------+----+-------------------
(3192,7) | 1 | 0.589303761254996
(1 row)
-- 查看最小 val 的存储
select ctid,id,val from test where val=(select min(val) from test);
ctid | id | val
-------+--------+------------------------
(0,1) | 806540 | 0.00000218348577618599
(1 row)
-- 收缩表,分析表,收集统计信息。
vacuum analyze test;
-- 查看列的离散程度,值越接近0,表示越离散,越接近1,表示存储比较有顺序
-- 说明目前表是根据 val 有序存储的。
select correlation from pg_stats where tablename='test' and attname='val';
correlation
-------------
1
(1 row)
select correlation from pg_stats where tablename='test' and attname='id';
correlation
-------------
0.00133778
(1 row)
-- 查询表,索引文件,都变了。说明cluster重建表和索引。
select pg_relation_filepath('test'::regclass);
pg_relation_filepath
----------------------
base/16385/64283
(1 row)
select pg_relation_filepath('test_id_idx'::regclass);
pg_relation_filepath
----------------------
base/16385/64289
(1 row)
select pg_relation_filepath('test_val_idx'::regclass);
pg_relation_filepath
----------------------
base/16385/64290
(1 row)
-- 表锁
-- session 1
mytest=# begin;
BEGIN
mytest=# cluster test USING test_id_idx ;
CLUSTER
-- session 2
mytest=# select * from test limit 1;
等待......
-- session 3
select pid,locktype,database,relation,granted,mode,b.relname from pg_locks a,pg_class b where a.relation=b.oid;
pid | locktype | database | relation | granted | mode | relname
-------+----------+----------+----------+---------+---------------------+-----------------------------------
22891 | relation | 16385 | 3455 | t | AccessShareLock | pg_class_tblspc_relfilenode_index
22891 | relation | 16385 | 2663 | t | AccessShareLock | pg_class_relname_nsp_index
22891 | relation | 16385 | 2662 | t | AccessShareLock | pg_class_oid_index
22891 | relation | 16385 | 1259 | t | AccessShareLock | pg_class
22891 | relation | 16385 | 11645 | t | AccessShareLock | pg_locks
21609 | relation | 16385 | 2679 | t | AccessShareLock | pg_index_indexrelid_index
21609 | relation | 16385 | 2678 | t | AccessShareLock | pg_index_indrelid_index
21609 | relation | 16385 | 2610 | t | AccessShareLock | pg_index
21609 | relation | 16385 | 3455 | t | AccessShareLock | pg_class_tblspc_relfilenode_index
21609 | relation | 16385 | 2663 | t | AccessShareLock | pg_class_relname_nsp_index
21609 | relation | 16385 | 2662 | t | AccessShareLock | pg_class_oid_index
21609 | relation | 16385 | 2685 | t | AccessShareLock | pg_namespace_oid_index
21609 | relation | 16385 | 2684 | t | AccessShareLock | pg_namespace_nspname_index
21609 | relation | 16385 | 2615 | t | AccessShareLock | pg_namespace
21609 | relation | 16385 | 1259 | t | AccessShareLock | pg_class
21609 | relation | 16385 | 64276 | t | AccessShareLock | test_val_idx
21609 | relation | 16385 | 64276 | t | AccessExclusiveLock | test_val_idx
21609 | relation | 16385 | 64272 | t | AccessExclusiveLock | pg_toast_64269
21609 | relation | 16385 | 64275 | t | AccessShareLock | test_id_idx
21609 | relation | 16385 | 64275 | t | AccessExclusiveLock | test_id_idx
21609 | relation | 16385 | 64269 | t | ShareLock | test
21609 | relation | 16385 | 64269 | t | AccessExclusiveLock | test
22829 | relation | 16385 | 64269 | f | AccessShareLock | test
(23 rows)