author:chenjunwen 2021-4-21
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Mycat2是分库分表型数据库(中间件),具有逻辑库,逻辑表概念,其中对于分片表类型,使用特定的规则组织'行数据'在多个物理表中存储.而SQL查询分片表的时候,正确使用谓词,Mycat2分析出仅需扫描的物理表,则可在执行阶段大大减少需要使用的连接,IO耗时,因为谓词不符合数据分布,查询的结果集就是空的.(v1.18提供索引字段分析)
在分库分表数据库中,使用不同的数据定位字段减少扫描的范围,它们是分表键,分库键,全局二级索引等.下推它们有着索引字段分析相似的功能.索引字段分析在数据库中至关重要.通常我们判断SQL能否使用哪种扫描数据方式就可以大致判断SQL的查询效率,对于分库分表中间件来说,尽可能减少扫描范围,甚至严格保证扫描的存储节点只有一个存储节点才是正确的用法.
索引字段分析的工作过程
非DNF检查
首次,优化器会提取下压到表扫描算子上的谓词,并把他们做disjunction(DNF)转换,试图得到一组or相邻的表达式,如果该表达式的数量是1,则表示该组表达式没有or运算,则可继续进行谓词分析,否则不满足谓词分析约束.
RexNode:{id = 1 or id = 2} → List<RexNode>[{id = 1},{id = 2}]
即
W=P1∨P2∨P3∨...Pn
特殊表达式扩展
其次,对谓词表达式扩展.在这里我们可以把一些特殊意义的表达式扩展,比如
id between 1 and 3 → 1 <= id and id <= 3
这样的好处与括号()表达优先级差不多,表示该表达式是一个整体,它们不被CNF/DNF影响.
CNF扩展
然后,对谓词进行CNF分析.得到一组and相邻的表达式.
RexNode:{id = 1 and id = 2} → List<RexNode>[{id = 1},{id = 2}]
即
W=P1^P2^P3^...Pn
索引应用
因为分片表可能存在多个索引信息,它们依次应用CNF扩展的结果.
提取索引字段
使用谓词检查语法检查and表达式中的每个表达式,提取scan_binary_expr这个层次的语法树,检查其中的字段是否索引字段,把它们转换成谓词节点并依照遍历顺序收集起来,与常规的解析器不同不符合语法的部分不会发生异常,直接跳过.
谓词检查语法
and_expr : scan_binary_expr 'AND' scan_binary_expr
scan_binary_expr : left_expr '=' right_expr
| left_expr '<' right_expr
| left_expr '>' right_expr
| left_expr '<=' right_expr
| left_expr '>=' right_expr
| right_expr '=' left_expr
| right_expr '<' left_expr
| right_expr '>' left_expr
| right_expr '<=' left_expr
| right_expr '>=' left_expr
| ...
right_expr : LITERAL | DYNAMIC_PARAM | CAST LITERAL
left_expr : COLUMN | cast_expr
cast_expr : CAST right_expr | CAST left_expr
谓词分解
将谓词分解为等值查询,范围查询,剩余查询三种类型
type = 'famliy' and score < 60 and score >=0
即
Wquery=Pequal^Prange^Presidual
Pequal : type = 'famliy'
Prange : score < 60
而索引谓词分析的目标则是提取Pequal或者Prange
对于相同的字段,为了减少扫描范围,显然Pequal总是比Prange更优
一些规约
Pequal^Prange→Pequal
Pequal^Prange^Presidual→Pequal
Pequal^Presidual→Pequal
Prange^Presidual→Prange
索引最左匹配原则
做左到右尽可能扫描指定的运算符,遇到不是需要的运算符则停止扫描
分解点查询谓词节点
应用索引最左匹配原则(做左到右尽可能扫描=的条件),检查是否点查询并把它们转换成点查询条件组,即可下推索引谓词组,而不能转换的谓词节点构成剩余条件组.
分解范围查询谓词节点
与分解点查询谓词节点相似,范围查询也是应用索引最左匹配原则(做左到右尽可能扫描>=,>等条件),检查是否点查询并把它们转换成上界/下界条件组,即可下推索引谓词组,而不能转换的谓词节点构成剩余条件组.这里的上下界条件组中每个条件不具有between语义.上界与下界是独立的条件.
score < 60 and score >=0 → [{score <60},{score >= 0}]
注解选择索引结果
最后,可能得到一组索引信息分析得到的结果,如果谓词分析器带有了注解要求的索引,在结果中有,则返回它的索引结果.(所以错误的注解可能导致无法使用真正有效的索引)
最终的索引分析结果
对它们的权重进行排序,返回权重最高的索引信息.
索引结果转换至分片条件
每个索引谓词都有它们的类型,比如点查询或者范围查询.对于点查询,可以直接调用分片算法的点查接口就可以得到存储节点的信息.而对于范围查询,我们可以检查上界下界条件,并进一步把它们转换成查询区间,然后调用分片算法的范围查询接口即可.
键的优先级
索引结果可能存在以下情况
一个索引结果有多个不同的字段
多个索引结果,这里仅讨论多个索引结果之间如何挑选最优的.
如果一个谓词中出现多个字段,而这些字段中有多个是可以定位数据分布,但是它们的执行代价,扫描范围可能相同也可能不相同,有些需要额外的IO,连接才可以完成数据定位.这个情况下,我们需要定义这些定位数据分布的索引字段之间的优先级,从中选择最有效的字段来定位数据.一般来说,存在以下规则.
等值查询总是比范围查询更优
分表键总是比分库键更优
...
对于难以判断那种索引更优或者索引性能随着数据量改变的情况,可以使用代价分析判断.