MySQL·源码分析·null reject谓词

Note:
本文背景大部分描述来自于 MySQL 官网,感兴趣的可以看原文描述
outer join simple

背景

outer join 的简化

  • right JOIN 的处理

MySQL 通常在解析阶段,就将 RIGHT JOIN 转换为 LEFT JOIN 的等效查询,例如:

`(T1, ...) RIGHT JOIN (T2, ...) ON P(T1, ..., T2, ...)`

等价于

(T2, ...) LEFT JOIN (T1, ...) ON P(T1, ..., T2, ...)

JOIN 的驱动表顺序变成在,T1 INNER JOIN t2 ON P(T1,T2) 变成 T1, T2, P(T1, T2)
但优化器对于驱动表顺序的选择依然有限,仅能考虑 T1 在前的情况,可以进一步尝试

  • inner JOIN 转换

例如:

SELECT * T1 FROM T1 LEFT JOIN T2 ON P1(T1,T2) WHERE P(T1,T2) AND R(T2)

如果该 SQL 按着此顺序执行,优化器只能按着 T1 驱动 T2 顺序执行,可可能会产生非常低效率的执行计划。

相反,如果 WHERE 条件是一个 null-rejected 的谓词,MySQL 可以将此类查询转换为一个非 outer join(inner join).

一个条件如果对于所有 NULL-complemented 的行来说,都会被评估为 FALSE 或者 UNKWON,则该条件对于 outer join 而言是 null-rejected.

null-rejected

一个条件如果对于所有 NULL-complemented 的行来说,都会被评估为 FALSE 或者 UNKWON,则该条件对于 outer join 而言是 null-rejected.

例如,对于以下外部连接:

T1 LEFT JOIN T2 ON T1.A=T2.A

以下条件会被视为 null-rejected,因为对于任何一个 NULL-complemented 的行,此条件都不可能为 true

T2.B IS NOT NULL 
T2.B > 3 T2.C <= T1.C 
T2.B < 2 OR T2.C > 1

而以下条件不会被视为 null-rejected,因为对于任何一个 NULL-complemented 的行,此条件可能为 true

T2.B IS NULL 
T1.B < 3 OR T2.B IS NOT NULL 
T1.B < 3 OR T2.B > 3

一个条件对于 outer join 而言,为 null-rejected 的通用规则为:

  • It is of the form A IS NOT NULL, where A is an attribute of any of
    the inner tables
  • It is a predicate containing a reference to an inner table that evaluates to UNKNOWN when one of its arguments is NULL
  • It is a conjunction containing a null-rejected condition as a conjunct
  • It is a disjunction of null-rejected conditions

一个条件对于 outer join 查询中的一个 outer join 可能是 null-rejected 但对于另一个不是 null-rejeced.

例如,下面 WHERE 条件对于第二个 outer join 是 null-rejected 的,但对第一个 outer join 不是:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A LEFT JOIN T3 ON T3.B=T1.B WHERE T3.C > 0如果一个 WHERE 条件对于一个 outer join 而言是一个 null-rejected 的话,则 outer join 可以转换为 inner join.
例如,上述 SQL 可以转换为:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A
                 INNER JOIN T3 ON T3.B=T1.B
WHERE T3.C > 0

这样,原有仅能考虑 T1,T2,T3 的联接顺序就可以再额外考虑 T3,T1,T2 的联接方式。

进一步优化

一个外连接操作的转换可能会触发另一个外连接操作的转换。因此,查询:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A
                 LEFT JOIN T3 ON T3.B=T2.B
WHERE T3.C > 0

首先转换为查询:

SELECT * FROM T1 LEFT JOIN T2 ON T2.A=T1.A
                 INNER JOIN T3 ON T3.B=T2.B
WHERE T3.C > 0

这相当于查询:

SELECT * FROM (T1 LEFT JOIN T2 ON T2.A=T1.A), T3 
WHERE T3.C > 0 AND T3.B=T2.B

剩余的外连接操作也可以用内连接代替,因为条件 T3.B=T2.B 被拒绝为空。这会导致查询完全没有外部连接:

SELECT * FROM (T1 INNER JOIN T2 ON T2.A=T1.A), T3
WHERE T3.C > 0 AND T3.B=T2.B

有时优化器成功替换了嵌入外连接操作,但无法转换嵌入外连接。以下查询:

SELECT * FROM T1 LEFT JOIN
              (T2 LEFT JOIN T3 ON T3.B=T2.B)
              ON T2.A=T1.A
WHERE T3.C > 0

转换为:

SELECT * FROM T1 LEFT JOIN 
                 (T2 INNER JOIN T3 ON T3.B=T2.B) 
                 ON T2.A=T1.A
WHERE T3.C > 0

只能将其重写为仍包含嵌入外连接操作的表单:

SELECT * FROM T1 LEFT JOIN
              (T2,T3)
              ON (T2.A=T1.A AND T3.B=T2.B)
WHERE T3.C > 0

任何在查询中转换嵌入外连接操作的尝试都必须考虑嵌入外连接的连接条件和 WHERE 条件。在这个查询中,嵌入外连接的 WHERE 条件不是拒绝空值,但是嵌入外连接的连接条件 T2.A=T1.A AND T3.C=T1.C 是拒绝空值:

SELECT * FROM T1 LEFT JOIN
              (T2 LEFT JOIN T3 ON T3.B=T2.B)
              ON T2.A=T1.A AND T3.C=T1.C 
WHERE T3.D > 0 OR T1.D > 0

因此,查询可以转换为:

SELECT * FROM T1 LEFT JOIN
                            (T2, T3)
                            ON T2.A=T1.A AND T3.C=T1.C AND T3.B=T2.B 
WHERE T3.D > 0 OR T1.D > 0```

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Validation 是一种基于注解的数据校验框架,可以对 Java 对象进行校验,常用于 Web 表单数据的校验。其核心原理是基于 Java 标准库中的 JSR-303 规范,通过注解标记 Java 类的字段,然后使用 Validator 接口对标记的字段进行校验。 Spring Validation 的校验流程大致如下: 1. 在 Controller 层接收表单数据,将数据封装成 Java 对象。 2. 对 Java 对象进行校验,检测是否符合预定规则。 3. 如果校验失败,返回错误信息。 Spring Validation 的核心接口是 Validator,其定义如下: ```java public interface Validator { boolean supports(Class<?> clazz); void validate(Object target, Errors errors); } ``` 其中,supports 方法用于判断该 Validator 是否支持校验指定的类型,validate 方法用于对指定的对象进行校验。 Spring Validation 内部使用了一个 Errors 对象来记录校验错误信息,如下所示: ```java public interface Errors { void reject(String errorCode, Object[] errorArgs, String defaultMessage); void rejectValue(String field, String errorCode, Object[] errorArgs, String defaultMessage); boolean hasErrors(); } ``` 其中,reject 方法用于记录全局错误信息,rejectValue 方法用于记录字段错误信息,hasErrors 方法用于判断是否存在校验错误信息。 Spring Validation 是通过反射机制读取 Java 对象的注解信息来完成校验的。在执行校验时,Spring Validation 会将 Java 对象的每个字段和对应的约束注解信息一一对应,然后根据注解信息进行校验。 Spring Validation 的分析较为复杂,主要涉及到反射、注解、AOP 等技术,需要深入了解 Spring 框架的原理和机制。如果需要深入学习 Spring Validation 的码,可以阅读 Spring 码中的 Validation 相关模块。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

抡着鼠标扛大旗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值