TiDB 源代码学习: ranger 模块代码分析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 对数据库技术有一定了解的同行们,应该对 索引前缀匹配 的概念不陌生. 在 TiDB 中 ranger 模块在前缀匹配机制中发挥了一定的作用,所以我想好好了解一下这个模块的代码.ranger 模块介绍ranger 模块重要的入口是 DetachCondAndBuildRangeForIndex 以及 DetachCondAndBuildRangeForTable 两个函数.本文以 DetachCondAndBuildRangeForIndex 函数为主要的分析对象,下面简称这个函数位 DCBRDCBR 的入参是:某个索引信息,主要是用里面的列信息(包含哪些列,以及它们在索引当中

对数据库技术有一定了解的同行们,应该对 索引前缀匹配 的概念不陌生. 在 TiDB 中 ranger 模块在前缀匹配机制中发挥了一定的作用,所以我想好好了解一下这个模块的代码.

ranger 模块介绍
ranger 模块重要的入口是 DetachCondAndBuildRangeForIndex 以及 DetachCondAndBuildRangeForTable 两个函数.

本文以 DetachCondAndBuildRangeForIndex 函数为主要的分析对象,下面简称这个函数位 DCBR

DCBR 的入参是:

某个索引信息,主要是用里面的列信息(包含哪些列,以及它们在索引当中的顺序)
扫描时所有可用的筛选条件
它的作用可以细分为 3 点:

根据索引的列信息,从筛选条件当中解析出可以用来做索引扫描的筛选条件,我们称为 accessConds
根据 accessConds 计算索引扫描的 ranges
从筛选条件中保留那些无法作为 accessConds 的条件,并返回
我们称这些条件为 filterConds
如果 DCBR 返回的 filterConds 不为空,那么查询数据时,在完成索引扫描以后,还需要使用 filterConds 过滤一边数据
简单示例
举个简单例子,假如现在有一个表:

create table (a int, b int, c int, index idx_ab(a, b));
我们用下面这条查询语句进行查询:

select * from t where a = 1 and b > 2 and c = 3;
系统在衡量使用索引 idx_ab 扫描的效率时,会调用 DCBR 方法计算 ranges, DCBR 得到的入参是:

索引 idx_ab 的信息,主要是使用里面的列信息
筛选条件 [(a = 1), (b > 2), (c = 3)]
DCBR 方法执行过程中:

会从筛选条件当中提取出 a = 1, b > 2 这两个条件作为 accessConds 返回
c = 3 不在索引列当中,无法用在索引扫描, 放入 filterConds 并返回
根据 a = 1, b > 2 两个条件计算索引扫描的 range (为 [[1 3, 1 +inf)] ) , 并返回
需要补充的是, 即使索引是 (a, b, c), c 列也无法用在索引扫描,这也是前缀匹配原则的缘故.

整体流程
对于像上面提到的这个例子 a = 1 and b > 2 and c = 3, 查询条件比较简单,所以代码中很多特殊的处理逻辑并没有起作用,具体步骤:

应根据索引列的顺序,先依次从条件当中找能够匹配上的 eq/in 条件,直到某一列无法找到这类条件为止
在这个例子里,会依次为 a 列和 b 列找 eq/in 条件, QQ号码买号最后只会找到一个条件 a = 1
如果第 1 步已经为所有的列找到了筛选条件,那么剩余的条件放入 filterConds 中,然后使用找到的 accessConds 计算索引扫描的 ranges,并返回
这个 sql 里,筛选条件并没有匹配到所有的索引列,所以不会在这步结束
如果第 1 步没有为所有列找到筛选条件,那么为第一个没找到条件的列(我们称它为 lastCol)从剩余的条件中寻找非 eq/in 类型的条件
本例里, lastCol 是 b,为 b 找的范围查询类型的条件是 b > 2
lastCol 的条件解析完以后,会根据这些条件来计算 range,并把剩余的条件加入到 filterConds 里
本例里 accessConds 是 a = 1 和 b > 2, filterConds 是 c = 3 , ranges 是 [[1 3, 1 +inf)]
对复杂条件的支持
除了支持上面例子中的简单查询条件(也就是多个条件用 and 串联的情况). DCBR 函数还要支持从多个 and/or 组合的条件中提取 accessConds,计算ranges.比如下面这个语句:

select * from t where (a > 1 and a < 3) or (a > 5 or a < );
需要补充说明的是,数据库会采用树形结构来表示查询条件,这个 sql 中,查询条件会组成下面这样的树形结构.

or
and
a > 1
a < 3
or
a > 2
a < 10
处理这类既有 and 又有 or 的查询条件.会先对条件进行一个 flatten 处理.

flatten 操作会把能够提升层级的 or 节点提升上来,经过 flatten 处理以后,会得到一个条件数组, 本次sql的处理结果是 (a > 1 and a < 3) , a > 2 , a < 10 这三个条件组成的数组

完成 flatten 处理以后,会分别计算数组中每个条件的 accessConds 和 ranges, 计算方式和最开头的简单查询条件的计算方式基本一样.然后把得到的 accessConds 和 ranges 合并,会计算ranges 的并集作为最终的 ranges 结果.

最终得到的 range 结果 (-inf, 0), (1, 3), (5, +inf),为了方便理解,这里只给出了 a 列的范围.

提前终止的场景
有的时候查询条件可能直接可以计算为 false,比如 a > 10 and a < 1;还有 a = 1 and a = 2, ranger 在计算过程中,如果发现某一列的条件计算结果是 false,就会终止整个计算过程,返回空的 ranges.

filterConds 的计算问题
如果是简单的查询条件, accesssConds 和 filterConds 其实很容易分辨,而且彼此互补影响的.但是对于复杂场景 filterConds 就比较难以提取了.

比如下面这个例子:

select * from t where (a > 1 and a < 2 and c > 10) or (a > 5 or a < );
和前面提到的例子相比,查询条件当中多了 c > 10 这个条件. accessConds 并没有发生变化.但是 filterConds 不再为空,而是多了 (a > 1 and a < 2 and c > 10) 这个条件.

ranger 如果在解析 accessConds 时,发现除了解析出来的 accessConds,还剩余了其他条件,这个时候会把整个条件加入到 filterConds 中.

回到这个例子里,ranger 在处理 (a > 1 and a < 2 and c > 10) 这个条件的时候,能够提取出来作为 accessConds 的是 a > 1, a < 2 这两个条件,但是还剩下一个 c > 10 ,这时 ranger 就会把整个 a > 1 and a <2 and c > 10 作为一个 filterConds 保留.

更多的示例
关于 ranger 这块的逻辑,大家可以看一下 TiDB 中提供的 测试用例Range ,里面除了上面描述的场景为还包含了其他一些场景的测试用例:

对 like 条件的 range 计算逻辑
对 not 条件的 range 计算逻辑
同一列有多个 eq/in 条件时,对 accessConds 的合并逻辑

目录
相关文章
|
3月前
|
SQL 存储 资源调度
实时计算 Flink版操作报错合集之启动项目时报错缺少MySqlValidator类,是什么原因
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
3月前
|
消息中间件 Kubernetes 监控
实时计算 Flink版操作报错合集之在编译源码时遇到报错:无法访问,该如何处理
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
5月前
|
分布式计算 DataWorks 安全
DataWorks产品使用合集之跑python3脚本,已按照文档安装上模块,提示找不到模块,是什么问题
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
36 0
|
6月前
|
关系型数据库 Java 分布式数据库
实时计算 Flink版操作报错合集之在使用 Python UDF 时遇到 requests 包的导入问题,提示 OpenSSL 版本不兼容如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
108 5
|
6月前
|
Java atlas 网络安全
Flink CDC编译问题之编译atlas报错如何解决
Flink CDC编译指的是将Flink CDC源代码转换成可执行程序的过程,可能会涉及到依赖管理和环境配置等问题;本合集将介绍Flink CDC编译的步骤、常见错误及其解决办法,以确保顺利完成编译过程。
|
SQL Oracle 关系型数据库
「集成架构」2020年最好的15个ETL工具(第二部)
「集成架构」2020年最好的15个ETL工具(第二部)
|
Java atlas Apache
数据治理一-Atlas2.1编译踩坑之路
数据治理一-Atlas2.1编译踩坑之路
434 0
|
存储 算法 索引
OushuDB 用户指南图算法之GQL脚本命令
OushuDB 用户指南图算法之GQL脚本命令
62 0
|
测试技术 Go 数据库
Go开发技巧和踩坑分享 | 代码结构 调试技巧 配置文件 元数据
分享一下最近使用GoFrame开发go项目的经验分享。
178 0
下一篇
无影云桌面