查询优化器使用大量的查询转换来产生新的语义相等的SQL语句。在那些查询转换中,根据用于决定是否应用它们的方法,可以分为两种途径。
Ø 基于启发式的查询转换(Heuristic-based query
transformations)是在满足特定条件时应用的。在大多数情况下它们预计都会引出更好的执行计划。
Ø 基于成本的查询转换(Cost-based query
transformations)是根据成本估算器计算的成本而应用的,它们会引出与原始语句相比成本更低的执行计划。
下面的章节介绍了二十几种查询转换并提供了相应的用例。目的不是对这些转换高谈阔论,而是为你提供一些头绪去了解在逻辑优化阶段引擎内部都发生了什么。因此,没有给出关于先决条件或限制性的详细信息。同时注意一些查询转换实际上可能会更加强大,或只有在最近的版本中才可用。所以,并非本章描述的每种查询转换在早前的版本中都可用,比如在版本10.2和11.1中。
注意 我试图让接下来的例子尽可能简单。结果就是,乍看之下,某些查询转换似乎只有在处理劣质的SQL语句时才可能用得到。劣质的意思是指包含多余或冲突操作的SQL语句。但你必须考虑到查询优化器不得不去处理比示例中要复杂得多的SQL语句。
试想一下,一个查询引用了几个视图而这些视图又引用了其他视图的情况,或者由通用用途的工具和专门的查询工具生成的查询语句。当查询优化器把所有的东西放在一起,出现多余或冲突操作的情况会屡见不鲜。
此外,查询优化器能识别奇怪的情况并避免执行不必要的处理。还有,一些查询转换允许你按最自然、可读的方式书写SQL语句,而不用为性能牺牲清晰性。实际上,一些查询转换是非常常见的SQL优化技术,当手工应用时,会产生不易读的SQL语句。
1.1.1 计数转换
计数转换(Count
Transformation)的目的是将count(列)表达式转化为count(*)。引入这个查询转换是因为相比count(列),处理count(*)时在索引使用方面有更多的选择空间。计数转换基于启发式的查询转换,可以在count函数引用的列中关联NOT NULL约束时进行应用(但是检查约束时不能用于此用途)。注意计数转换也会将count(1)这样的表达式转化为count(*)。
下面的例子基于count_transformation.sql脚本,阐明了这种查询转换。注意原始的查询包含count(n2)这个表达式:
SELECT count(n2) FROM t;
如果有一个NOT NULL约束定义在n2列上,计数转换就会将count(n2)转换为count(*)并生成以下查询:
SELECT count(*) from t;
1.1.2 公共子表达式消除
公共子表达式消除(common
sub-expression elimination) 的目的是移除重复的谓词从而避免多次处理同一个操作。这是一种基于启发式的查询转换。
下面的例子来自common_subexpr_elimination.sql这个脚本,注意两个分隔的谓词是如何重叠的。实际上,所有满足第一个条件的数据行都满足第二个条件:
SELECT * FROM t WHERE(n1=1 AND n2=2) OR
(n1=1);
公共子表达式消除可移除冗余的谓词,并产生以下查询:
SELECT * FROM t WHERE n1=1;
你是不是对留下的谓词感到惊讶?如果仔细考虑一下,会发现n1=1足以满足这个查询了,而n2=2却仍然需要考虑n1=1的情况。




