带你读 MySQL 源码:Where 条件怎么过滤记录?( 五 )


调用 item->val_bool() 的返回值是 false,说明当前读取的记录不匹配该条件 。
ignore_unknown() 的返回值也是 false,表示包含 NULL 值的 where 条件的比较结果(UNKNOWN)不按 false 处理,而是要等到 while 循环结束之后,根据 null_value 属性的值(true 或 false)算总帐 。

这是由 Item_cond_and 对象控制的行为,而不是 and 连接的某个 where 条件控制的行为 。
!(null_value = https://www.isolves.com/it/sjk/MYSQL/2023-05-26/item->null_value)) 表达式的值为 false,说明该条件包含 NULL 值,那么它就是 ignore_unknown() = false 时需要等到 while 循环结束之后,根据 null_value 属性的值算总帐的条件 。
该条件之后的其它 where 条件,不会导致 while 循环被提前中止(这样执行流程才能来到 return null_value ? 0 : 1) 。
此时,null_value 属性的值为 true,null_value ? 0 : 1 表达式的值为 0,说明当前读取的记录不匹配 and 连接的 N 个 where 条件 。
Item_func_eq::val_int()// sql/item_cmpfunc.cclonglong Item_func_eq::val_int() {assert(fixed == 1);int value = https://www.isolves.com/it/sjk/MYSQL/2023-05-26/cmp.compare();return value == 0 ? 1 : 0;}这里调用的 cmp.compare() 就是前面介绍的 Arg_comparator::compare() 方法 。
对于示例 SQL 来说,Arg_comparator::compare() 调用的是 Arg_comparator::compare_int_signed() 方法,返回值只有 3 种:
  • -1:表示 where 条件操作符左边的值小于右边的值 。
  • 0:表示 where 条件操作符左边的值等于右边的值 。
  • 1:表示 where 条件操作符左边的值大于右边的值 。
我们以 id = 5 的记录和示例 SQL 的 where 条件 i1 = 50 为例,介绍 Item_func_eq::val_int() 的逻辑:
带你读 MySQL 源码:Where 条件怎么过滤记录?

文章插图
i1 字段值为 50,对 where 条件 i1 = 50 调用 cmp.compare(),得到的返回值为 0(即 value = https://www.isolves.com/it/sjk/MYSQL/2023-05-26/0) 。
value =https://www.isolves.com/it/sjk/MYSQL/2023-05-26/= 0 ? 1 : 0 表达式的值为 1,这就是 Item_func_eq::val_int() 的返回值,表示 id = 5 的记录匹配 where 条件 i1 = 50 。
Item_cond_or::val_int()// sql/item_cmpfunc.cclonglong Item_cond_or::val_int() {assert(fixed == 1);List_iterator_fast<Item> li(list);Item *item;null_value = https://www.isolves.com/it/sjk/MYSQL/2023-05-26/false;while ((item = li++)) {if (item->val_bool()) {null_value = false;return 1;}if (item->null_value) null_value = true;...}return 0;}我们以 id = 8 的记录和示例 SQL 的 where 条件 i1 = 50 or i1 = 80 为例,介绍 Item_cond_or::val_int() 的逻辑:
带你读 MySQL 源码:Where 条件怎么过滤记录?

文章插图
Item_cond_or 对象的 list 属性包含 2 个条件:i1 = 50、i1 = 80,List_iterator_fastli(list) 根据 list 构造一个迭代器 。
对于 id = 8 的记录,i1 字段值为 80,while 循环每次迭代一个 where 条件:
第 1 次迭代,对 where 条件 i1 = 50 调用 item->val_bool(),返回值为 false,不进入 if (item->val_bool()) 分支 。
if (item->null_value) 条件不成立,不执行 null_value = https://www.isolves.com/it/sjk/MYSQL/2023-05-26/true 。
第 2 次迭代,对 where 条件 i1 = 80 调用 item->val_bool(),返回值为 true,进入 if (item->val_bool()) 分支 。
设置 Item_cond_or 对象的 null_value 属性值为 false,表示 Item_cond_or 所代表的 or 连接的 where 条件(i1 = 50、i1 = 80)都不包含 NULL 值 。
return 1,这就是 Item_cond_or::val_int() 的返回值,表示 id = 8 的记录匹配 where 条件 i1 = 50 or i1 = 80 。
总结本文介绍了 SQL 的 where 条件中包含 and、or 的实现逻辑:
从存储引擎读取一条记录之后,对 and 连接的 N 个 where 条件(N >= 2)调用 item->val_bool() 的返回值必须全部等于 true,记录才匹配 and 连接的 N 个 where 条件 。
Item_cond_and::val_int() 的代码不多,但是这个方法中调用了 ignore_known() 用于控制怎么处理 where 条件包含 NULL 值的场景,代码细节并不太好理解,所以花了比较长的篇幅介绍 Item_cond_and::val_int() 方法的逻辑,需要多花点时间去理解其中的逻辑 。
从存储引擎读取一条记录之后,对 or 连接的 N 个 where 条件(N >= 2)调用 item->val_bool(),只要其中一个返回值等于 true,记录就匹配 or 连接的 N 个 where 条件 。
本文转载自微信公众号「一树一溪」




推荐阅读