Oracle 2005 年出了一个 30 多页的小册子,《Query Optimization in Oracle Database10g Release 2》,介绍了常见的优化器技术。
我是做 SQL 执行的,优化部分只了解皮毛,从没有系统学习过。本系列逐个学习和介绍,自我提升,也帮助他人。
这个技术原理也很简单,初中就学习过:
(a * b) + (a * c) = a * (b + c)
在这个式子里,如果 a 是一个常量,那么这个变换没什么意义,但是考虑如果 a 是一个函数,改写成:
(f(x) * b) + (f(x) * c) = f(x) * (b + c)
显然,式子右侧更加高效,它把 f(x)
抽取出来,只需计算一次即可。
回到 SQL 里看看什么是公共子表达式消除:
SELECT * FROM EMP, DEPT
WHERE
(EMP.DEPTNO = DEPT.DEPTNO AND LOC = 'DALLAS' AND SAL > 100000)
OR
(EMP.DEPTNO = DEPT.DEPTNO AND LOC = 'DALLAS' AND JOB_TITLE = 'VICE PRESIDENT')
这里,EMP.DEPTNO = DEPT.DEPTNO AND LOC = 'DALLAS'
就是上面式子里的 f(x)
,改写后变成:
SELECT * FROM EMP, DEPT
WHERE EMP.DEPTNO = DEPT.DEPTNO AND LOC = ‘DALLAS’ AND
(SAL > 100000 OR JOB_TITLE = 'VICE PRESIDENT');
改写之前,从 DEPT 吐出的每一行数据都会计算两次 LOC='DALLAS'
表达式,改写后只需要计算一次。
NOTE:理解这个技术,一定要知道“计算机是非常愚蠢”的,你不帮它提取,它就算两遍!我们人类遇到这种问题时,都会自动做公共表达式抽取,计算机可不会。不过,一旦你教会了计算机这个规则,它可以做得比人类好得多。为什么?假设这个表达式有 10 页纸,人类可能就观察不出来了,计算机还是能轻松解决。