# CLUSTER
#### 功能描述
使用指定索引对指定表执行聚簇排序操作，该索引必须已存在于目标表内。
- GaussDB在执行表聚簇排序操作后，该表将基于索引信息进行物理存储。CLUSTER是一次性操作，当该表被更新之后，更改的内容不会被重新聚簇，即系统不会试图按照索引顺序对新的存储内容及更新记录进行重新聚簇。
- GaussDB在执行表聚簇排序操作后，会记录该表所使用的聚簇索引。后续执行CLUSTER *table_name* ;命令时，数据库将自动基于先前记录的聚簇索引进行重新聚簇。用户可通过ALTER TABLE *table_name* CLUSTER ON *index_name* ;指定后续聚簇排序操作的聚簇索引，或通过ALTER TABLE *table_name*SET WITHOUT CLUSTER;清除该表的聚簇索引设置。
- 无参数CLUSTER命令会对当前用户所拥有的数据库中所有已聚簇表进行重新聚簇。若系统管理员调用该命令，则对所有已聚簇表重新聚簇排序。
- GaussDB在执行表聚簇排序操作时，会对该表请求ACCESS EXCLUSIVE锁，从而避免在CLUSTER操作完成前对该表执行其他的操作（包括读写）。
 
#### 注意事项
- 只有行存B-Tree索引支持CLUSTER聚簇排序操作。
- 当表数据访问模式为随机读取时，数据存储顺序无显著影响；若存在频繁按特定索引访问的场景，且索引对数据具有分组效应，使用CLUSTER可提升查询性能。
- 当查询条件涉及索引范围扫描或索引键对应多行数据时，CLUSTER操作可有效提升查询性能。若索引已标识出首条匹配记录所在的存储页，其余匹配行通常位于同一页内，从而减少磁盘I/O并加速查询。
- GaussDB在执行表聚簇排序操作时，会先创建一个按照索引顺序建立的表的临时备份，同时也建立表上的每个索引的临时备份。因此，聚簇过程中需要保证磁盘上有足够的剩余空间（至少为表大小与全部索引大小之和）。
- 优化器依赖表的排序统计信息进行查询规划。对表执行聚簇排序操作后，需运行ANALYZE操作以更新优化器的排序统计信息。若未及时更新，优化器可能基于过时信息生成非最优的查询执行计划。
- 不允许在事务中执行CLUSTER聚簇排序操作。
- 如果没有将GUC参数xc_maintenance_mode设置为on，那么CLUSTER聚簇排序操作将忽略所有的系统表。
- 对于全局二级索引（GSI）：
  - 在单个分区上执行CLUSTER命令或通过CLUSTER \[VERBOSE\];对已聚簇表重新进行聚簇后，查询语句若访问全局二级索引将报错，需执行REINDEX INDEX重建全局二级索引以恢复查询。
  
  - 对带有全局二级索引（GSI）的表执行CLUSTER操作后，需要重新收集GSI的统计信息，即调用ANALYZE GLOBAL INDEX gsi_name FOR TABLE table_name语句。具体操作请参见[ANALYZE \| ANALYSE](https://support.huaweicloud.com/distributed-ref-v10-gaussdb/gaussdb-08-0221.html)。
   
- 通过表达式索引进行聚簇排序操作时，需拥有此表达式索引的重建索引的权限。
 
#### 语法格式
- 对表进行聚簇排序操作
  ```
  CLUSTER [ VERBOSE ] table_name [ USING index_name ];
  ```
  ![](https://support.huaweicloud.com/distributed-ref-v10-gaussdb/figure/zh-cn_image_0000002793708105.png "点击放大")
  
- 对分区进行聚簇排序操作
  ```
  CLUSTER [ VERBOSE ] table_name PARTITION ( partition_name ) [ USING index_name ];
  ```
  ![](https://support.huaweicloud.com/distributed-ref-v10-gaussdb/figure/zh-cn_image_0000002764469494.png "点击放大")
  
- 对已聚簇表重新进行聚簇排序操作
  ```
  CLUSTER [ VERBOSE ];
  ```
  ![](https://support.huaweicloud.com/distributed-ref-v10-gaussdb/figure/zh-cn_image_0000002764309566.png "点击放大")
  
 
#### 参数说明
- **VERBOSE**
  可选。用于控制是否输出操作的详细进度信息。
  
- **table_name**
  需要进行聚簇排序操作的指定表名称。
  取值范围：已存在的表名称。
  
- **USING index_name**
  对表/分区进行聚簇排序时，指定的索引名称。
  取值范围：已存在的索引名称。
  ![](https://support.huaweicloud.com/distributed-ref-v10-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
  首次对表进行聚簇排序操作时，必须指定该选项；当再次对表进行聚簇排序操作时，可省略指定index_name，数据库将自动基于先前记录的聚簇索引进行重新聚簇。
  
- **partition_name**
  对分区进行聚簇排序时，指定的分区名称。
  取值范围：已存在的分区名称。
  
 
#### 示例
- 对表进行聚簇排序操作：
  ```
  --建表并向表中插入数据。
  gaussdb=# CREATE TABLE test_c1(id int, name varchar(20));
  gaussdb=# CREATE INDEX idx_test_c1_id ON test_c1(id);
  gaussdb=# INSERT INTO test_c1 VALUES (3,'Joe'),(1,'Jack'),(2,'Scott');
  --查看。
  gaussdb=# SELECT * FROM test_c1;
   id | name  
  ----+-------
    3 | Joe
    1 | Jack
    2 | Scott
  (3 rows)
  --聚簇排序。
  gaussdb=# CLUSTER test_c1 USING idx_test_c1_id;
  --查看。
  gaussdb=# SELECT * FROM test_c1;
   id | name  
  ----+-------
    1 | Jack
    2 | Scott
    3 | Joe
  (3 rows)
  --删除。
  gaussdb=# DROP TABLE test_c1;
  ```
  
- 对已聚簇的表重新进行聚簇排序操作：
  ```
  --建表。
  gaussdb=# CREATE TABLE test(col1 int,CONSTRAINT pk_test PRIMARY KEY (col1));
  --第一次聚簇排序不带USING关键字报错。
  gaussdb=# CLUSTER test;
  ERROR:  there is no previously clustered index for table "test"
  --聚簇排序。
  gaussdb=# CLUSTER test USING pk_test;
  --插入数据。
  gaussdb=# INSERT INTO test VALUES (1),(99),(10),(8);
  --对已聚簇的表重新进行聚簇排序。
  gaussdb=# CLUSTER VERBOSE test;
  INFO:  clustering "public.test" using index scan on "pk_test"(dn_6001 pid=3672)
  INFO:  "test": found 0 removable, 4 nonremovable row versions in 1 pages(dn_6001 pid=3672)
  DETAIL:  0 dead row versions cannot be removed yet.
  CPU 0.00s/0.00u sec elapsed 0.01 sec.
  CLUSTER
  --删除。
  gaussdb=# DROP TABLE test;
  ```
  
- 对分区进行聚簇排序操作：
  ```
  --建表并向表中插入数据。
  gaussdb=# CREATE TABLE test_c2(id int, info varchar(4)) PARTITION BY RANGE (id)(
      PARTITION p1 VALUES LESS THAN (11),
      PARTITION p2 VALUES LESS THAN (21)
  );
  gaussdb=# CREATE INDEX idx_test_c2_id1 ON test_c2(id);
  gaussdb=# INSERT INTO test_c2 VALUES (6,'ABBB'),(2,'ABAB'),(9,'AAAA');
  gaussdb=# INSERT INTO test_c2 VALUES (11,'AAAB'),(19,'BBBA'),(16,'BABA');
  --查看。
  gaussdb=# SELECT * FROM test_c2;
   id | info 
  ----+------
    6 | ABBB
    2 | ABAB
    9 | AAAA
   11 | AAAB
   19 | BBBA
   16 | BABA
  (6 rows)
  --对分区p2进行聚簇排序。
  gaussdb=# CLUSTER test_c2 PARTITION (p2) USING idx_test_c2_id1;
  --查看。
  gaussdb=# SELECT * FROM test_c2;
   id | info 
  ----+------
    6 | ABBB
    2 | ABAB
    9 | AAAA
   11 | AAAB
   16 | BABA
   19 | BBBA
  (6 rows)
  --删除。
  gaussdb=# DROP TABLE test_c2;
  ```
  
 
