作者:杨涛涛
资深数据库专家,专研 MySQL 十余年。擅长 MySQL、PostgreSQL、MongoDB 等开源数据库相关的备份恢复、SQL 调优、监控运维、高可用架构设计等。目前任职于爱可生,为各大运营商及银行金融企业提供 MySQL 相关技术支持、MySQL 相关课程培训等工作。
本文来源:原创投稿
*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
OceanBase 从索引和主表的关系来讲,有两种索引:局部索引和全局索引。
局部索引等价于我们通常说的本地索引,与主表的数据结构保持一对一的关系。局部索引没有单独分区的概念,一般来讲,主表的分区方式决定局部索引的分区方式,也就是说假设主表有10个分区,那么对于每个分区来讲,都有一个对应的局部索引。
全局索引区别于局部索引,与主表数据结构保持一对多、多对多的关系,全局索引主要应用于分区表。对于分区表来讲,一个非分区全局索引对应主表的多个分区;一个分区全局索引也对应主表的多个分区,同时主表每个分区也对应多个全局索引的索引分区。
引入全局索引的目标就是弥补局部索引在数据过滤上的一些不足,比如避免分区表的全分区扫描,把过滤条件下压到匹配的表分区中。
针对查询过滤条件来讲,局部索引和全局索引的简单使用场景总结如下:
1. 带分区键的查询,适合用局部索引。这也是分区表设计的初衷,以过滤条件来反推分区表的设计。
比如语句:select * from p1 where id = 9; id 为分区键,可以直接定位到具体的表分区partitions(p9),仅需扫描一行记录。
<mysql:5.6.25:ytt>explain select * from p1 where id = 9\G *************************** 1. row *************************** Query Plan: ================================== |ID|OPERATOR |NAME|EST. ROWS|COST| ---------------------------------- |0 |TABLE GET|p1 |1 |46 | ================================== Outputs & filters: ------------------------------------- 0 - output([p1.id], [p1.r1], [p1.r2]), filter(nil), access([p1.id], [p1.r1], [p1.r2]), partitions(p9) 1 row in set (0.005 sec)
2. 不带分区键的查询有两个考虑方向,主要在于能否克服全局索引的缺点:全局索引势必会带来查询的分布式执行!
(1)表的并发写不大,可以考虑用全局索引。
(2)表的并发写很大,用全局索引与否就有待商榷, 可以根据当前的业务模型做个压力测试,取一个折中点。
比如以下语句, 全局索引idx_r2_global基于非分区字段r2,执行计划如下:算子1需要去底层各个节点分布式扫描(DISTRIBUTED TABLE SCAN)。
<mysql:5.6.25:ytt>explain select * from p1 where r2 = 30\G *************************** 1. row *************************** Query Plan: ============================================================= |ID|OPERATOR |NAME |EST. ROWS|COST| ------------------------------------------------------------- |0 |TABLE LOOKUP |p1 |101 |395 | |1 | DISTRIBUTED TABLE SCAN|p1(idx_r2_global)|101 |48 | ============================================================= ...
3. 对于需要在非主键、非分区键的字段上建立唯一索引的业务来讲,可以有两个考虑方向:
(1)给这个字段创建局部索引,但是需要带上完整的分区键。 不推荐这种方式,一来是需要更改过滤条件,增加分区键;二来增加索引本身的数据冗余。
比如在MySQL租户下创建这样的索引会报错:
<mysql:5.6.25:ytt>create unique index udx_r1 on p1(r1) local; ERROR 1503 (HY000): A UNIQUE INDEX must include all columns in the table's partitioning function
如果创建本地索引,则需要加上完整分区键:
<mysql:5.6.25:ytt>create unique index udx_r1_local on p1(r1,id) local; Query OK, 0 rows affected (3.012 sec)
(2)给这个字段创建全局索引,不需要带上完整的分区键。 强烈推荐的方式!
<mysql:5.6.25:ytt>create unique index udx_r1_global on p1(r1) global; Query OK, 0 rows affected (1.950 sec)