KingbaseES 全局索引
概述:在分区表上创建的索引可分为全局索引和本地索引。全局索引包括全局非分区索引(Global Nonpartitioned Indexes)和全局分区索引(Global Partitioned Indexes)。
- 全局分区索引(Global Partitioned Indexes)是指与分区表有不同分区方式的索引,它是在分区表的所有分区数据基础上创建的分区索引,目前KingbaseES 暂不支持。
- 本地索引(本地分区索引,Local Partitioned Indexes),是指在每个表分区上单独创建的索引,是一种局部索引,也是一种分区索引,某一个索引分区只能索引到一个表分区。
- 需要启用 enable_globalindexscan = on; 才能使用全局索引。目前只支持select 操作使用全局索引。
1、全局索引例子
create table t1_part(id1 integer,id2 integer,id3 integer) partition by range(id1) ( partition part01 values less than(10000), partition part02 values less than(20000), partition part03 values less than(30000), partition part04 values less than(40000), partition part05 values less than(50000), partition part06 values less than(60000), partition part07 values less than(70000), partition part08 values less than(80000), partition part09 values less than(90000), partition part10 values less than(maxvalue) ); create unique index idx1_t1_part on t1_part(id1) global ; create unique index idx2_t1_part on t1_part(id2) global ; create index idx3_t1_part on t1_part(id2) global ;
注意:并不是global 就一定是全局索引。当创建全局索引时,首先尝试创建本地索引。当不满足本地索引的条件(唯一索引的索引列不包括全部分区列或者分区条件为表达式)时会创建全局索引。同样,启用分区表上的主键/唯一约束时,先尝试创建本地索引,不满足时则创建全局唯一索引。可以看到,只有第二个索引才是全局索引。
test=# \di+ idx1_t1_part List of relations Schema | Name | Type | Owner | Table | Size | Description --------+--------------+-------------------+--------+---------+---------+------------- public | idx1_t1_part | partitioned index | system | t1_part | 0 bytes | (1 row) test=# \di+ idx2_t1_part List of relations Schema | Name | Type | Owner | Table | Size | Description --------+--------------+--------------+--------+---------+------------+------------- public | idx2_t1_part | global index | system | t1_part | 8192 bytes | (1 row) test=# \di+ idx3_t1_part List of relations Schema | Name | Type | Owner | Table | Size | Description --------+--------------+-------------------+--------+---------+---------+------------- public | idx3_t1_part | partitioned index | system | t1_part | 0 bytes | (1 row)
全局索引支持条件索引,不支持全局分区索引。全局索引不支持排他约束。
2、全局索引存在的限制
DML操作不允许针对子表 使用全局索引。
test=# delete from t1_part_part04 where id2=31111; --使用全局索引访问子表 ERROR: cannot modify partition t1_part_part04 with global indexes, maintain the partitioned table directly
test=# select * from t1_part_part04 where id2=31111; id1 | id2 | id3 -----+-----+----- (0 rows) test=# delete from t1_part where id2=31111; DELETE 1
3、分区索引与全局索引的性能比较
继续以上的例子,插入100000 条记录:
insert into t1_part select generate_series(1,100000),generate_series(1,100000),generate_series(1,100000);
来看执行性能的差异:
test=# declare test-# v_result integer; test-# begin test-# for i in 1..100000 loop test-# select id3 into v_result from t1_part where id1=i; test-# end loop; test-# end; test-# / ANONYMOUS BLOCK Time: 1320.094 ms (00:01.320) test=# test=# declare test-# v_result integer; test-# begin test-# for i in 1..100000 loop test-# select id3 into v_result from t1_part where id2=i; test-# end loop; test-# end; test-# / ANONYMOUS BLOCK Time: 4281.198 ms (00:04.281)
比较结果分析:
1、local 索引的访问效率是 global 索引3倍左右
2、Oracle 的rowid 直接定位数据文件的数据块,而KingbaseES 的ctid 只是对象文件的第几块,因此,KingbaseES 的全局索引需要先定位该 ctid 属于哪个分区的。
3、KingbaseES 全局索引在索引值包含对象 OID,通过OID找到对应的文件,再通过ctid 访问。这必然有性能的损耗,但这是因为ctid 的结构所导致的。
4、全局索引暂时不支持index_only_scan
KINGBASE研究院