自动FORCE INDEX

本文为您介绍PolarDB-X的自动FORCE INDEX机制。

背景信息

当一条查询SQL(逻辑SQL)发往PolarDB-X时,PolarDB-X的计算节点的优化器会将其分成可下推和不可下推的两部分,可下推的部分也被称为物理SQL。大多数情况下,物理SQL会直接发送给存储节点,由PolarDB-X的存储节点基于代价选择合适的局部索引。

由于代价模型缺陷、统计信息不准确等问题,基于代价选择索引的模式可能会出现索引选错。因此在某些确定性场景下,计算节点会基于规则选择合适的局部索引,使用FORCE INDEX指定索引将其添加到物理SQL中,干预存储节点的索引选择,减少错误发生的概率。

支持版本

  • 对于5.4.18-17181576之前的实例,无自动FORCE INDEX机制。

  • 对于初次购买版本在5.4.18-17181576之前并升级到5.4.18-17181576及以上的实例,默认关闭自动FORCE INDEX机制。

  • 对于新购实例

    • 计算节点组件版本低于5.4.18,无自动FORCE INDEX机制。

    • 计算节点组件版本为5.4.18,小版本低于17181576,无自动FORCE INDEX机制;小版本不低于17181576,默认开启自动FORCE INDEX机制。

    • 计算节点组件版本为5.4.19,发布日期早于2024-07-10之前,无自动FORCE INDEX机制;发布日期不早于2024-07-10,默认开启自动FORCE INDEX机制。

    • 计算节点组件版本高于5.4.19,默认开启自动FORCE INDEX机制。

说明

注意事项

  • 对于只涉及单表、广播表的查询,不会触发自动FORCE INDEX。

  • 对于下推到存储节点的多表关联物理SQL,不会触发自动FORCE INDEX。

  • 对于下推到单分片的查询,不会触发自动FORCE INDEX。

  • 局部索引选择(local index selection)的优先级从高到低,如下所示:

    • 手动FORCE INDEX。

    • 自动FORCE INDEX。

    • XPlan索引选择。

    • 存储节点索引选择。

原理

主键索引和唯一索引

主键索引和唯一索引自动FORCE INDEX的条件如下:

  • 收集等值条件的列,收集到的列都是表中的原始列。

  • 主键索引或唯一索引被收集到的列覆盖。

普通二级索引

普通二级索引自动FORCE INDEX的条件如下:

  • 剔除不能利用索引的条件后,剩余条件仅包含等值条件。

  • 收集等值条件与ORDER BY的列,收集到的列都是表中的原始列。

  • 收集到的列被索引前缀覆盖。

示例

示例表example,包含唯一索引UK与联合索引LK,示例如下:

CREATE TABLE `example` (
	`a` int(11) NOT NULL,
	`b` int(11) NOT NULL,
	`c` int(11) NOT NULL,
	`d` int(11) NOT NULL,
	UNIQUE KEY `UK` (`a`, `b`),
	KEY `LK` (`b`, `c`, `d`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4
PARTITION BY KEY(`a`)
PARTITIONS 4

场景一:

收集到的列为(a,b),c,可以覆盖索引UK,会自动执行FORCE INDEX(UK),示例如下:

select * from example where (a,b) in ((1,2),((3,4))) and c = 1 order by d
mysql> explain select * from example where (a,b) in ((1,2),((3,4))) and c = 1 order by d;
+------------------------+
| LOGICAL EXECUTIONPLAN                                                      
+------------------------+
| MergeSort(sort="d ASC")                                                    
|   LogicalView(tables="example[p1,p4]", shardCount=2, sql="SELECT `a`, `b`, `c`, `d` FROM `example` AS `example` FORCE INDEX(UK) WHERE ((((`a`, `b`)) IN(?)) AND (`c` = ?)) ORDER BY `d`", pruningInfo="all size:2*2(part), pruning size:2") |
| HitCache:false                                                             
| Source:PLAN_CACHE                                                          
| TemplateId: 3148a498                                                       
+------------------------+

场景二:

收集到的列为c,不可以覆盖索引UK,不会自动执行FORCE INDEX(),示例如下:

select * from example where (a+1,b) in ((1,2),((3,4))) and c = 1 order by d
mysql> explain select * from example where (a+1,b) in ((1,2),((3,4))) and c = 1 order by d;
+------------------------+
| LOGICAL EXECUTIONPLAN    
+------------------------+
| MergeSort(sort="d ASC")       
|   LogicalView(tables="example[p1,p2,p3,p4]", shardCount=4, sql="SELECT `a`, `b`, `c`, `d` FROM `example` AS `example` WHERE (((((`a` + ?), `b`)) IN(?)) AND (`c` = ?)) ORDER BY `d`") |
| HitCache:false            
| Source:PLAN_CACHE       
| TemplateId: 5ad46a6e  
+------------------------+

场景三:

收集到的列为b,c,可以被索引LK前缀匹配,会自动执行FORCE INDEX(LK),示例如下:

select * from example where (b) in (1,2) and a > b order by c
mysql> explain select * from example where (b) in (1,2) and a > b order by c;
+------------------------+
| LOGICAL EXECUTIONPLAN  
+------------------------+
| MergeSort(sort="c ASC") 
|   LogicalView(tables="example[p1,p2,p3,p4]", shardCount=4, sql="SELECT `a`, `b`, `c`, `d` FROM `example` AS `example` FORCE INDEX(LK) WHERE ((`a` > `b`) AND (`b` IN(?))) ORDER BY `c`") |
| HitCache:false          
| Source:PLAN_CACHE       
| TemplateId: 3a4124bd    
+------------------------+

场景四:

剔除不能利用索引的条件后,剩余条件包含非等值条件c>1,不会自动执行FORCE INDEX,示例如下:

select * from example where (b) in (1,2) and c > 1 order by d
mysql> explain select * from example where (b) in (1,2) and c > 1 order by d;
+------------------------+
| LOGICAL EXECUTIONPLAN
+------------------------+
| MergeSort(sort="d ASC")
|   LogicalView(tables="example[p1,p2,p3,p4]", shardCount=4, sql="SELECT `a`, `b`, `c`, `d` FROM `example` AS `example` WHERE ((`b` IN(?)) AND (`c` > ?)) ORDER BY `d`") |
| HitCache:false                                                                
| Source:PLAN_CACHE                                                             
| TemplateId: f01b447f                                                          
+------------------------+