定义
002中多次提到表达式这个概念,那么什么是表达式呢?我们定义表达式:
- 数字和字段引用是一个表达式:比如
1
,2
,4
,15
,a
,id
…… -
<表达式> <运算符号> <表达式>
:运算符号链接起来的两个表达式,也是表达式。比如1+2
,id*2
等。 -
(<表达式>)
: 括号括起来的表达式也是表达式(括号用于影响求值顺序),比如(1)
,(1+2)
是表达式。
其中运算符号可以是数学运算符加减乘除(+-*/),逻辑运算符(AND OR)等。我们来看个的例子:
2 * (id + 4)
上面这个是表达式吗?我们这样检查:
- 根据规则1,
id
是表达式,3
是表达式,4
是表达式 - 根据规则2,
id + 4
是表达式 - 根据规则3,
(id + 4)
是表达式 - 根据规则2,
2 * (id + 4)
是表达式
SELECT语句的本质
SELECT语句本质上就是对SELECT后面跟着的表达式进行求值。那么怎么对表达式进行求值呢?规则如下:
- 如果有FROM引用表,那么把FROM引用的表中的每一行取出来,如果没有,直接进行步骤3
- 把每一行拿到的字段的值代入到表达式
- 进行数学运算
举例:
SELECT id*2 FROM items
这个SELECT语句的求值过程:
- 把每一行字段的值
items
表里面取出来 - 并带入到表达式,由于
items
表有几百万行,所以我们代入的结果变成了几百万个表达式求值:<第1行的id> * 2
<第2行的id> * 2
<第3行的id> * 2
- ...
<最后1行的id> * 2
- 进行数学运算。假设
第1行的id
是5,那么就等同于求值5 * 2
。这是一个数学表达式,就按照人类理解的数学去进行计算,得到结果10
。依次类推,算出每一行的值。
再举例:
SELECT 1 FROM items
这个SELECT语句的求值过程:
- 把每一行字段的值
items
表里面取出来 - 并带入到表达式,由于
items
表有几百万行,所以我们代入的结果变成了几百万个表达式求值:-
1
(第1行的求值) -
1
(第2行的求值) -
1
(第3行的求值) - ...
-
1
(最后1行的求值)
-
- 这里比较有意思,虽然表达式里面没有引用任何字段,但根据规则还是把
items
表里面字段的值取出来,进行代入。但是代入并没有产生任何影响,然后进行数学运算。所以我们得到了几百万行1
。
再看一个例子:
SELECT 1+2
由于没有引用字段,直接进行数学运算,得到结果3
。
WHERE语句的本质
类似的,WHERE语句的本质就是:
- 把FROM引用的表中的每一行取出来
- 把每一行拿到的字段的值代入到表达式
- 如果表示式结果为真的话就保留,否则过滤掉,然后再进行SELECT求值过程。
举例:
SELECT id*2 FROM items WHERE id < 100000
WHERE检验过程:
- 把每一行字段的值
items
表里面取出来 - 并带入到表达式,由于
items
表有几百万行,所以我们代入的结果变成了几百万个表达式求值:<第1行的id> < 100000
<第2行的id> < 100000
<第3行的id> < 100000
- ...
<最后1行的id> < 100000
- 根据表达结果是否为真决定这行是否被过滤掉。举例,比如
第一行的id
为5,那么5 < 100000
这个表达式的结果为真,所以第一行保留。比如最后一行的id
为1234567
,那么1234567 < 100000
这个表达式的结果为假,所以最后一行被过滤掉。
表达式求值的异常
不是所有表达式都有意义,没有意义的表达式,会出现异常,得到不可预测的结果,要尽量避免。
- 比如
1/0
,除0在数学上没有定义,没有意义。 - 比如
"a"+1
,字符串和数字相加,没有意义。
具体的原因,请看后面教程:理解类型。