基于湖库一体架构,统一管理结构化、半结构化与非结构化等多模态数据,一个系统承载事务处理、实时分析与 AI 工作负载。
全局索引
更新时间:2023-07-18 17:25:59
全局索引的创建规则是在索引属性中指定 GLOBAL 关键字。与局部索引相比,全局索引最大的特点是全局索引的分区规则跟表分区是相互独立的,全局索引允许指定自己的分区规则和分区个数,不一定需要跟表分区规则保持一致。
使用限制
在分布式环境中,全局索引不可避免的会涉及到分布式事务和跨机的查询,因此全局索引依赖 GTS 维护全局的一致性快照,所以全局索引只能在 GTS 开启的时候使用。如果没有开启 GTS,则创建全局索引失败。
obclient> SET GLOBAL ob_timestamp_service = LTS;
Query OK, 0 rows affected
obclient> CREATE TABLE tbl(col1 INT,col2 INT, PRIMARY KEY(col1));
Query OK, 0 rows affected
obclient> CREATE INDEX gkey ON tbl1(col2) GLOBAL
PARTITION BY RANGE(col2)
(PARTITION p0 VALUES LESS THAN(100),
PARTITION p1 VALUES LESS THAN(200),
PARTITION p2 VALUES LESS THAN(300)
);
ERROR 1235 (0A000): create global index when GTS is off not supported
创建全局索引前,您可以通过 SHOW VARIABLES 语句查看 ob_timestamp_service 变量取值。
obclient> SHOW GLOBAL VARIABLES LIKE 'ob_timestamp_service';
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| ob_timestamp_service | LTS |
+----------------------+-------+
1 row in set
可以通过 ob_timestamp_service 变量设置 GTS。
obclient> SET GLOBAL ob_timestamp_service = GTS;
Query OK, 0 rows affected
创建全局索引
如果主表没有指定分区键或者指定的分区数为 1,那么主表也只有一个分区,这个时候,全局索引的数据和主表数据的物理位置是相互绑定在一起的,无论是迁移还是副本 Leader 发生切换,它们都是作为一个整体进行变换,不会存在中间状态。如果全局索引的分区规则和主表的分区规则相同并且分区数相同,这时推荐创建一个局部索引。 一方面是因为全局索引的维护代价更大;另一方面是因为全局索引无法保证和主表分区的物理位置相同,除非将其和主表指定在一个表组中。
创建全局索引
创建 Hash 分区一级分区表 tbl1_h,并为其创建采用 Range 分区的全局索引 tbl1_h_idx1。
obclient> CREATE TABLE tbl1_h(col1 INT PRIMARY KEY,col2 INT)
PARTITION BY HASH(col1) PARTITIONS 5;
Query OK, 0 rows affected
obclient> CREATE INDEX tbl1_h_idx1 ON tbl1_h(col2) GLOBAL
PARTITION BY RANGE(col2)
(PARTITION p0 VALUES LESS THAN(100),
PARTITION p1 VALUES LESS THAN(200),
PARTITION p2 VALUES LESS THAN(300)
);
Query OK, 0 rows affected
创建全局唯一索引
创建非模板化 Range + List 分区表 tbl2_f_rl,并为其创建全局唯一索引 tbl2_f_rl_idx1。
obclient> CREATE TABLE tbl2_f_rl(col1 INT,col2 INT)
PARTITION BY RANGE(col1)
SUBPARTITION BY LIST(col2)
(PARTITION p0 VALUES LESS THAN(100)
(SUBPARTITION sp0 VALUES IN(1,3),
SUBPARTITION sp1 VALUES IN(4,6),
SUBPARTITION sp2 VALUES IN(7,9)),
PARTITION p1 VALUES LESS THAN(200)
(SUBPARTITION sp3 VALUES IN(1,3),
SUBPARTITION sp4 VALUES IN(4,6),
SUBPARTITION sp5 VALUES IN(7,9))
);
Query OK, 0 rows affected
obclient> CREATE UNIQUE INDEX tbl2_f_rl_idx1 ON tbl2_f_rl(col1) GLOBAL;
Query OK, 0 rows affected
分区裁剪
全局索引的分区键一定是索引键本身,因此在使用全局索引的过程中就会指定索引分区键的查询条件,我们可以针对索引的分区规则进行分区裁剪,在查询到索引键值后可以利用索引表中存储的主键信息计算出主表的分区位置,进而对主表也能进行快速的分区定位,避免扫描主表的所有分区,因此对于无法指定主表分区键的查询而言,全局索引在一定条件下能够加速查询的检索效率。
示例如下:
obclient> EXPLAIN SELECT /*+index(t1 gkey)*/ * FROM t1 WHERE b=1\G
*************************** 1. row ***************************
Query Plan: ==========================================
|ID|OPERATOR |NAME |EST. ROWS|COST |
------------------------------------------
|0 |TABLE LOOKUP|T1 |4950 |38645|
|1 | TABLE SCAN |T1(GKEY)|4950 |1115 |
==========================================
Outputs & filters:
-------------------------------------
0 - output([T1.A], [T1.B], [T1.C]), filter(nil),
partitions(p[0-4])
1 - output([T1.A]), filter(nil),
access([T1.A]), partitions(p1)
对于上述查询,首先通过 where 条件中的 b=1 条件裁剪出全局索引的分区 p1,然后对全局索引进行 table scan 操作以得到对应的主键。利用 table lookup 算子对主表进行精确的分区扫描以避免扫描主表的所有分区。