DQL/DML-DDL并发
表级DDL会给分区表施加8级锁,阻塞全部的DQL/DML操作。
分区级DDL会给分区表施加4级锁,并给目标分区施加8级锁。当DQL/DML与DDL作用不同分区时,支持二者执行层面的并发;当DQL/DML与DDL作用相同分区时,后触发业务会被阻塞。
如果并发的DDL与DQL/DML作用目标分区有重叠,由于串行阻塞,DQL/DML既可能先于DDL发生,也可能后于DDL发生,用户应该明确知晓其可能的预期结果。比如当Truncate与Insert作用同一分区时,如果Truncate先于Insert触发,则业务完成后目标分区存在数据,如果Truncate后于Insert触发,则业务完成后目标分区不存在数据。
业务在进行分区DDL维护操作时,应尽可能避免期间同时对目标分区进行DQL/DML操作。
DQL/DML-DDL跨分区并发
GaussDB Kernel支持跨分区的DQL/DML-DDL并发。
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') );
--并发case1,插入分区time_2011与清空分区time_2008互不阻塞 \parallel on INSERT INTO range_sales VALUES (455124, 92121433, '2011-09-17', 'X', 4513, 7, 17); ALTER TABLE range_sales TRUNCATE PARTITION time_2008 UPDATE GLOBAL INDEX; \parallel off --并发case2,指定分区time_2010查询与交换分区time_2009互不阻塞 \parallel on SELECT COUNT(*) FROM range_sales PARTITION (time_2010); ALTER TABLE range_sales EXCHANGE PARTITION (time_2009) WITH TABLE temp UPDATE GLOBAL INDEX; \parallel off --并发case3,对分区表range_ sales做更新与删除分区time_2008互不阻塞,这是因为更新SQL带条件剪枝到分区time_2010和time_2011上 \parallel on UPDATE range_sales SET channel_id = 'T' WHERE channel_id = 'X' AND time_id > '2010-06-01'; ALTER TABLE range_sales DROP PARTITION time_2008 UPDATE GLOBAL INDEX; \parallel off --并发case4,对分区表range_ sales的任何DQL/DML操作与新增分区time_2012互不阻塞,这是因为新增分区对其他进行的业务不可见 \parallel on DELETE FROM range_sales WHERE channel_id = 'T'; ALTER TABLE range_sales ADD PARTITION time_2012 VALUES LESS THAN ('2013-01-01'); \parallel off
DQL/DML-DDL同分区并发
GaussDB Kernel不支持同分区的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操作会被阻塞,阻塞完成后业务报错。
ERROR: partition xxxxxx does not exist on relation "xxxxxx"
DETAIL: this partition may have already been dropped by cocurrent DDL operations SPLIT PARTITION
- MERGE分区
MERGE分区会将多个分区合并为一个分区,如果合并后的分区与其中一个旧分区A名字相同,逻辑上视为相同分区。期间触发的目标分区DQL/DML操作会被阻塞,阻塞完成后,根据目标分区类型判断,如果目标分区是旧分区A,则作用于新分区;如果目标分区为其他旧分区,则业务报错。
ERROR: partition xxxxxx does not exist on relation "xxxxxx"
DETAIL: this partition may have already been dropped by cocurrent DDL operations MERGE PARTITION
- RENAME分区
RENAME分区不会变更分区结构信息,期间触发的DQL/DML操作不会出现任何异常,但会被阻塞,直到RENAME操作提交。
- MOVE分区
MOVE分区不会变更分区结构信息,期间触发的DQL/DML操作不会出现任何异常,但会被阻塞,直到MOVE操作提交。