
# 创建和管理索引
#### 背景信息
索引可以提高数据的访问速度，但同时也增加了插入、更新和删除操作的处理时间。所以是否要为表增加索引，索引建立在哪些字段上，是创建索引前必须要考虑的问题。需要分析应用程序的业务处理、数据使用、经常被用作查询的条件或者被要求排序的字段来确定是否建立索引。
索引建立在数据库表中的某些列上。因此，在创建索引时，应该仔细考虑在哪些列上创建索引。
- 在经常需要搜索查询的列上创建索引，可以加快搜索的速度。
- 在作为主键的列上创建索引，强制该列的唯一性和组织表中数据的排列结构。
- 在经常使用连接的列上创建索引，可以加快连接的速度。
- 在经常需要根据范围进行搜索的列上创建索引，因为索引已经排序，其指定的范围是连续的。
- 在经常需要排序的列上创建索引，因为索引已经排序，这样查询可以利用索引的排序，加快排序查询时间。
- 在经常使用WHERE子句的列上创建索引，加快条件的判断速度。
- 在经常出现关键字ORDER BY、GROUP BY、DISTINCT后面的字段建立索引。
  ![](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
  - 索引创建成功后，系统会自动判断何时引用索引。当系统认为使用索引比顺序扫描更快时，就会使用索引。
  
  - 索引创建成功后，必须和表保持同步以保证能够准确地找到新数据，这样就增加了数据操作的负荷。因此请定期删除无用的索引。
  
  - 分区表索引分为LOCAL索引与GLOBAL索引，一个LOCAL索引对应一个具体分区，而GLOBAL索引则对应整个分区表。
    
 
- 在开启逻辑复制的场景下，如需创建包含系统列的主键索引，必须将该表的REPLICA IDENTITY属性设置为FULL或是使用USING INDEX指定不包含系统列的、唯一的、非局部的、不可延迟的和仅包括标记为NOT NULL的列的索引。
#### 操作步骤
创建分区表的步骤请参见[创建和管理分区表](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/gaussdb-42-0046.html#ZH-CN_TOPIC_0000002235458521)。
- 创建索引
  - 创建分区表LOCAL索引tpcds_web_returns_p2_index1，不指定索引分区的名称。
    ```
    gaussdb=# CREATE INDEX tpcds_web_returns_p2_index1 ON tpcds.web_returns_p2 (ca_address_id) LOCAL;
    ```
    当结果显示为如下信息，则表示创建成功。
    ```
    CREATE INDEX
    ```
    
  
  - 创建分区表LOCAL索引tpcds_web_returns_p2_index2，并指定索引分区的名称。
    ```
    gaussdb=# CREATE INDEX tpcds_web_returns_p2_index2 ON tpcds.web_returns_p2 (ca_address_sk) LOCAL
    (
        PARTITION web_returns_p2_P1_index,
        PARTITION web_returns_p2_P2_index TABLESPACE example3,
        PARTITION web_returns_p2_P3_index TABLESPACE example4,
        PARTITION web_returns_p2_P4_index,
        PARTITION web_returns_p2_P5_index,
        PARTITION web_returns_p2_P6_index,
        PARTITION web_returns_p2_P7_index,
        PARTITION web_returns_p2_P8_index
    ) TABLESPACE example2;
    ```
    当结果显示为如下信息，则表示创建成功。
    ```
    CREATE INDEX
    ```
    
  
  
  
  - 创建分区表GLOBAL索引tpcds_web_returns_p2_global_index。
    ```
    CREATE INDEX tpcds_web_returns_p2_global_index ON tpcds.web_returns_p2 (ca_street_number) GLOBAL;
    ```
    
   
- 修改索引分区的表空间
  - 修改索引分区*web_returns_p2_P2_index* 的表空间为example1。
    ```
    gaussdb=# ALTER INDEX tpcds.tpcds_web_returns_p2_index2 MOVE PARTITION web_returns_p2_P2_index TABLESPACE example1;
    ```
    当结果显示为如下信息，则表示修改成功。
    ```
    ALTER INDEX
    ```
    
  
  - 修改索引分区*web_returns_p2_P3_index* 的表空间为example2。
    ```
    gaussdb=# ALTER INDEX tpcds.tpcds_web_returns_p2_index2 MOVE PARTITION web_returns_p2_P3_index TABLESPACE example2;
    ```
    当结果显示为如下信息，则表示修改成功。
    ```
    ALTER INDEX
    ```
    
   
- 重命名索引分区
  执行如下命令对索引分区*web_returns_p2_P8_index* 重命名*web_returns_p2_P8_index_* new。
  ```
  gaussdb=# ALTER INDEX tpcds.tpcds_web_returns_p2_index2 RENAME PARTITION web_returns_p2_P8_index TO web_returns_p2_P8_index_new;
  ```
  当结果显示为如下信息，则表示重命名成功。
  ```
  ALTER INDEX
  ```
  
- 查询索引
  - 执行如下命令查询系统和用户定义的所有索引。
    ```
    gaussdb=# SELECT RELNAME FROM PG_CLASS WHERE RELKIND='i' or RELKIND='I';
    ```
    
  
  - 执行如下命令查询指定索引的信息。
    ```
    gaussdb=# \di+ tpcds.tpcds_web_returns_p2_index2
    ```
    
   
- 删除索引
  ```
  gaussdb=# DROP INDEX tpcds.tpcds_web_returns_p2_index1;
  gaussdb=# DROP INDEX tpcds.tpcds_web_returns_p2_index2;
  ```
  当结果显示为如下信息，则表示删除成功。
  ```
  DROP INDEX
  ```
  
GaussDB支持4种创建索引的方式请参见[表1]。
![](https://support.huaweicloud.com/centralized-devg-v3-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
- 索引创建成功后，系统会自动判断何时引用索引。当系统认为使用索引比顺序扫描更快时，就会使用索引。

- 索引创建成功后，必须和表保持同步以保证能够准确地找到新数据，这样就增加了数据操作的负荷。因此请定期删除无用的索引。
 
 表1索引方式 
| 索引方式  | 描述                                                                                                                              |
|:---|:---|
| 唯一索引  | 可用于约束索引属性值的唯一性，或者属性组合值的唯一性。如果一个表声明了唯一约束或者主键，则GaussDB自动在组成主键或唯一约束的字段上创建唯一索引（可能是多字段索引），以实现这些约束。目前，GaussDB只有B-Tree及UBTree可以创建唯一索引。 |
| 多字段索引 | 一个索引可以定义在表中的多个属性上。目前，GaussDB中的B-Tree支持多字段索引。                                                                                    |
| 部分索引  | 建立在一个表的子集上的索引，这种索引方式只包含满足条件表达式的元组。                                                                                              |
| 表达式索引 | 索引建立在一个函数或者从表中一个或多个属性计算出来的表达式上。表达式索引只有在查询时使用与创建时相同的表达式才会起作用。                                                                    |
   
- 创建一个普通表
  ```
  gaussdb=# CREATE TABLE tpcds.customer_address_bak AS TABLE tpcds.customer_address;
  INSERT 0 0
  ```
  

- 创建普通索引
  如果对于tpcds.customer_address_bak表，需要经常进行以下查询。
  ```
  gaussdb=# SELECT ca_address_sk FROM tpcds.customer_address_bak WHERE ca_address_sk=14888;
  ```
  通常，数据库系统需要逐行扫描整个tpcds.customer_address_bak表以查询所有匹配的元组。如果表tpcds.customer_address_bak的规模很大，但满足WHERE条件的只有少数几个（可能是零个或一个），则这种顺序扫描的性能较差。如果让数据库系统在ca_address_sk属性上维护一个索引，用于快速定位匹配的元组，则数据库系统只需要在搜索树上查询少数的几层就可以找到匹配的元组，这将会大幅提高数据查询的性能。同样，在数据库中进行更新和删除操作时，索引也可以提升这些操作的性能。
  使用以下命令创建索引。
  ```
  gaussdb=# CREATE INDEX index_wr_returned_date_sk ON tpcds.customer_address_bak (ca_address_sk);
  CREATE INDEX
  ```
  
- 创建唯一索引 在表tpcds.ship_mode_t1上的SM_SHIP_MODE_SK字段上创建唯一索引。
  ```
  gaussdb=# CREATE UNIQUE INDEX ds_ship_mode_t1_index1 ON tpcds.ship_mode_t1(SM_SHIP_MODE_SK);
  ```
  
- 创建多字段索引
  如果用户需要经常查询表tpcds.customer_address_bak中ca_address_sk是5050，且ca_street_number小于1000的记录，使用以下命令进行查询。
  ```
  gaussdb=# SELECT ca_address_sk,ca_address_id FROM tpcds.customer_address_bak WHERE ca_address_sk = 5050 AND ca_street_number < 1000;
  ```
  使用以下命令在字段ca_address_sk和ca_street_number上定义一个多字段索引。
  ```
  gaussdb=# CREATE INDEX more_column_index ON tpcds.customer_address_bak(ca_address_sk ,ca_street_number );
  CREATE INDEX
  ```
  
- 创建部分索引 如果只需要查询ca_address_sk为5050的记录，可以创建部分索引来提升查询效率。
  ```
  gaussdb=# CREATE INDEX part_index ON tpcds.customer_address_bak(ca_address_sk) WHERE ca_address_sk = 5050;
  CREATE INDEX
  ```
  
- 创建表达式索引
  假如经常需要查询ca_street_number小于1000的信息，执行如下命令进行查询。
  ```
  gaussdb=# SELECT * FROM tpcds.customer_address_bak WHERE trunc(ca_street_number) < 1000;
  ```
  可以为上述查询创建表达式索引：
  ```
  gaussdb=# CREATE INDEX para_index ON tpcds.customer_address_bak (trunc(ca_street_number));
  CREATE INDEX
  ```
  
- 删除tpcds.customer_address_bak表。
  ```
  gaussdb=# DROP TABLE tpcds.customer_address_bak;
  DROP TABLE
  ```
  
 
