尽量不在要where条件中,对列做计算。很多同学只知道规则,但是不知为什么。为了回答这个问题,本节将带你研究一下。

数据库的服务端,可以分为执行器存储引擎两部分。执行器负责解析SQL执行查询,存储引擎负责保存数据。

SQL是如何在执行器中执行的?

以下面SQL为例

select u.id, u.name, o.id
from users u inner join o on u.id = o.user.id
where u.id > 50

这个 SQL 语义是,查询用户 ID 大于 50 的用户的所有订单,这是很简单的一个联查,需要查询 users 和 orders 两张表,WHERE 条件就是,用户 ID 大于 50。

数据库收到查询请求后,需要先解析SQL语句,转换后的结构化数据,就是抽象语法树(AST,Abstract Syntax Tree)。

image.png

执行器解析AST之后,生成逻辑执行计划。执行计划可以理解为如何一步一步的执行查询和计算,最终得到执行结果的一个分步骤计划。

image.png

和SQL、AST不同的是,逻辑执行计划很像执行的程序代码了。执行计划很像编程语言的函数调用栈,外层调用内层的方法。所以理解执行计划,得从内往外看。

  1. 最内层的2个LogicalTableScan的含义是,把USER和ORDERS这两个表的数据拿出来
  2. 然后做一个LogincalJoin,Join条件是$0 = $6
  3. 然后执行一个过滤器,过滤没有用的行
  4. 做一个投影,过滤没用的列

如果,user 表有 1,000 条数据,订单表里面有 10,000 条数据,这 个 JOIN 操作需要遍历的行数就是 1,000 x 10,000 = 10,000,000 行。可见,这种从 SQL 的 AST 直译过来的逻辑执行计划,一般性能都非常差,所以,需要对执行计划进行优化。

如何对执行计划进行优化,不同的数据库有不同的优化方法,这一块儿也是不同数据库性能有差距的主要原因之一。优化的总体思路是,在执行计划中,尽早地减少必须处理的数据量。也就是说,尽量在执行计划的最内层减少需要处理的数据量。看一下简单优化后的逻辑执行计划: