技术分享 | OceanBase 使用全局索引的必要性

时间:2022-10-16 01:08:50

作者:杨涛涛

资深数据库专家,专研 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)
本文关键字:#全局索引# #本地索引#