
# DQL/DML-DDL并发
表级DDL、以及SPLIT/MERGE这两种分区DDL会给分区表施加8级锁，阻塞该分区表全部的DQL/DML操作。
ADD、DROP、EXCHANGE、TRUNCATE、MOVE、RENAME这六种分区级DDL会给分区表施加4级锁，并给目标分区施加8级锁。当DQL/DML与DDL作用不同分区时，支持二者执行层面的并发；当DQL/DML与DDL作用相同分区时，后触发业务会被阻塞。
![](https://support.huaweicloud.com/distributed-devg-v10-gaussdb/public_sys-resources/notice_3.0-zh-cn.png)
- 业务在进行分区DDL维护操作时，应尽可能避免期间同时对目标分区进行DQL/DML操作。
- 如果并发的DDL与DQL/DML作用目标分区有重叠，由于串行阻塞，DQL/DML既可能先于DDL发生，也可能后于DDL发生，用户应该明确知晓其可能的预期结果。比如当Truncate与Insert作用于同一分区时，如果Truncate先于Insert触发，则业务完成后目标分区存在数据，如果Truncate后于Insert触发，则业务完成后目标分区不存在数据。
- 如果分区表为bucket表，且表上存在全局索引，当执行MERGE、EXCHANGE以及SET TABLESPACE三种分区级DDL操作时会重建全局索引，期间阻塞表上DML业务。
 
#### DQL/DML-DDL跨分区并发
GaussDB支持跨分区的DQL/DML-DDL并发。
例如，定义如下分区表range_sales，下面给出了一些支持并发的例子。
```
gaussdb=# CREATE TABLE range_sales
(
    product_id     INT4 NOT NULL,
    customer_id    INT4 NOT NULL,
    time_id        DATE,
    channel_id     CHAR(1),
    type_id        INT4,
    quantity_sold  NUMERIC(3),
    amount_sold    NUMERIC(10,2)
)
PARTITION BY RANGE (time_id)
(
    PARTITION time_2008 VALUES LESS THAN ('2009-01-01'),
    PARTITION time_2009 VALUES LESS THAN ('2010-01-01'),
    PARTITION time_2010 VALUES LESS THAN ('2011-01-01'),
    PARTITION time_2011 VALUES LESS THAN ('2012-01-01')
);
gaussdb=# CREATE TABLE temp
(
    product_id     INT4 NOT NULL,
    customer_id    INT4 NOT NULL,
    time_id        DATE,
    channel_id     CHAR(1),
    type_id        INT4,
    quantity_sold  NUMERIC(3),
    amount_sold    NUMERIC(10,2)
);
```
分区表支持的并发业务可以为如下典型场景。
```
--并发case1，插入分区time_2011与清空分区time_2008互不阻塞
gaussdb=# \parallel on
gaussdb=# INSERT INTO range_sales VALUES (455124, 92121433, '2011-09-17', 'X', 4513, 7, 17);
gaussdb=# ALTER TABLE range_sales TRUNCATE PARTITION time_2008 UPDATE GLOBAL INDEX;
gaussdb=# \parallel off
--并发case2，指定分区time_2010查询与交换分区time_2009互不阻塞
gaussdb=# \parallel on
gaussdb=# SELECT COUNT(*) FROM range_sales PARTITION (time_2010);
gaussdb=# ALTER TABLE range_sales EXCHANGE PARTITION (time_2009) WITH TABLE temp UPDATE GLOBAL INDEX;
gaussdb=# \parallel off
--并发case3，对分区表range_sales做更新与删除分区time_2008互不阻塞，这是因为更新SQL带条件剪枝到分区time_2010和time_2011上
gaussdb=# \parallel on
gaussdb=# UPDATE range_sales SET channel_id = 'T' WHERE channel_id = 'X' AND time_id > '2010-06-01';
gaussdb=# ALTER TABLE range_sales DROP PARTITION time_2008 UPDATE GLOBAL INDEX;
gaussdb=# \parallel off
--并发case4，对分区表range_sales的任何DQL/DML操作与新增分区time_2012互不阻塞，这是因为新增分区对其他进行的业务不可见
gaussdb=# \parallel on
gaussdb=# DELETE FROM range_sales WHERE channel_id = 'T';
gaussdb=# ALTER TABLE range_sales ADD PARTITION time_2012 VALUES LESS THAN ('2013-01-01');
gaussdb=# \parallel off
```
#### DQL/DML-DDL同分区并发
GaussDB不支持同分区的DQL/DML-DDL并发，后触发业务会被先触发业务阻塞。
原则上，不建议用户在进行分区DDL时，同时对该分区进行DQL/DML操作，因为目标分区存在一个状态的突变过程，可能会导致业务的查询结果不符合预期。
当由于业务模型不合理或无法剪枝等场景导致的DQL/DML和DDL作用分区有重叠时，考虑以下两种场景：
场景一：先触发DQL/DML，再触发DDL。DDL会被阻塞，等待DQL/DML提交后再进行。
场景二：先触发DDL，再触发DQL/DML。DQL/DML会被阻塞，等待DDL提交后再进行，由于分区元信息在此期间发生变化，可能导致预期结果异常。为了保证数据一致性，预期结果按照如下规则制定。
- **ADD分区**
  ADD分区会产生一个新的分区，这个新分区对期间触发的DQL/DML操作均是不可见的，无阻塞期。
  
- **DROP分区**
  DROP分区会将已有分区进行删除，期间触发的目标分区DQL/DML操作会被阻塞，阻塞完成后跳过对该分区的处理。
  
- **TRUNCATE分区**
  TRUNCATE分区会清空已有分区的数据，期间触发的目标分区DQL/DML操作会被阻塞，阻塞完成后继续对该分区进行处理。
  注意期间触发的目标分区查询是查不到数据的，因为TRUNCATE操作提交后目标分区中不存有任何数据。
  
- **EXCHANGE分区**
  EXCHANGE分区会将一个已有分区与普通表进行交换，期间触发的目标分区DQL/DML操作会被阻塞，阻塞完成后继续对该分区进行处理，该分区的实际数据对应原普通表。
  例外：如果分区表上存在GLOBAL索引，EXCHANGE命令带有UPDATE GLOBAL INDEX子句，且期间触发的分区表查询使用了GLOBAL索引，由于无法查询到交换后分区上的数据，在阻塞完成后查询业务会报错。
  ERROR: partition xxxxxx does not exist on relation "xxxxxx"
  DETAIL: this partition may have already been dropped by cocurrent DDL operations EXCHANGE PARTITION
  
- **SPLIT分区**
  SPLIT分区当前会阻塞全表的DQL/DML操作，也包括目标分区本身。SPLIT提交后，DQL/DML操作会基于SPLIT完成后的分区表结构进行。
  
- **MERGE分区**
  MERGE分区当前会阻塞全表的DQL/DML操作，也包括目标分区本身。MERGE提交后，DQL/DML操作会基于MERGE完成后的分区表结构进行。
  
- **RENAME分区**
  RENAME分区不改变分区结构信息，期间触发的DQL/DML操作不会出现任何异常，但会被阻塞，直到RENAME操作提交。
  
- **MOVE分区**
  MOVE分区不改变分区结构信息，期间触发的DQL/DML操作不会出现任何异常，但会被阻塞，直到MOVE操作提交。
  ![](https://support.huaweicloud.com/distributed-devg-v10-gaussdb/public_sys-resources/notice_3.0-zh-cn.png)
  - 在DQL/DML业务期间，如果对执行DQL/DML操作的分区，连续同时做多次分区DDL操作，有低概率出现报错，报错原因：分区找不到，分区已经被DDL删除。
  
  - DQL/DML-DDL同分区并发有低概率出现业务死锁或者锁超时。原因：部分DQL/DML操作只在DN施加分区锁，若和DDL在不同DN的加锁顺序不一致则有概率导致死锁/锁超时。为避免死锁，可以设置GUC参数enable_partition_ddl_lowlevel_lock为off，但是会有性能影响，具体可参考GUC参数enable_partition_ddl_lowlevel_lock的说明。
    
 
