作者:杨涛涛
资深数据库专家,专研 MySQL 十余年。擅长 MySQL、PostgreSQL、MongoDB 等开源数据库相关的备份恢复、SQL 调优、监控运维、高可用架构设计等。目前任职于爱可生,为各大运营商及银行金融企业提供 MySQL 相关技术支持、MySQL 相关课程培训等工作。
本文来源:原创投稿
针对查询过滤条件来讲,局部索引和全局索引的简单使用场景总结如下:
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)表的并发写很大,用全局索引与否就有待商榷, 可以根据当前的业务模型做个压力测试,取一个折中点。
<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)
<mysql:5.6.25:ytt>create unique index udx_r1_global on p1(r1) global;
Query OK, 0 rows affected (1.950 sec)