当前位置: 代码迷 >> SQL >> 《Pro Oracle SQL》-chapter 5-5.6 Building Logical Expressions
  详细解决方案

《Pro Oracle SQL》-chapter 5-5.6 Building Logical Expressions

热度:232   发布时间:2016-05-05 14:58:12.0
《Pro Oracle SQL》--chapter 5--5.6 Building Logical Expressions

5.6 Building Logical Expresions 构建逻辑表达式 (page 140)
??? Once you understand the question that the statement you are writing needs to answer, you have to be able to build the SQL to provide the answer.? There are often many possible ways to express the same predicate logic.? Being able to formulate the conditions in a way that is easy to read and efficient requires you to think in ways you may not be used to.? Remember when I discussed the idea of thinking in sets versus thinking procedurally in Chapter 4?? There is a similar thought-shift that you may need to make in order to be able to build predicates for your SQL statements most efficiently.??
??? 当你理解了所写语句前需要解答的问题时,你必须通过写SQL来找出答案。有许多可行的方案表示同样的谓词逻辑(predicate logic)。为了能用易读且有效的方式公式化表示条件,你可能要用非同一般的方法思考。还记得我在第四章所讨论的用集合的方式思考而不是用过程的方式思考么?这里类似你也要做一次思维转移,来构建谓词让你的SQL语句更有效率。
??? The key is to learn some good Boolean logic techniques so that you don’t have to rely on only one
way to express conditional logic.? You may find that using Boolean logic expressions will always produce the most efficient plan operation choices (make sure to test alternatives thoroughly), but it’s good to know how to formulate different alternatives so you aren’t stuck with a single way to do things.
??? 关键是要学会一些好的布尔逻辑技术,让你不只是依赖于一种方式表达条件逻辑。你将发现使用布尔逻辑表达式总能产生最有效率的运算选择计划(确保一定彻底的测试替代方案)。知道(数据库)如何公式化表示不同的方案对你是有益的,这让你不会拘泥于只用一种方法做事情。
??? When I say conditional logic, I mean an expression something like “if X then Y” where X and Y are
both conditions.? In a WHERE clause, you might want to have a condition like if :GetAll <> 1 then empno = :empno.? In other words, if the value of the input bind variable named :GetAll is 1, then you want to? return all rows, but if :GetAll is not 1, then only return rows where empno is equal to the :empno bind variable supplied.? A WHERE clause to express this logic might be coded like this:
??? WHERE empno = CASE WHEN :GetAll <> 1 THEN :empno ELSE empno END ???

??? 当我说条件逻辑,我的意思是某个像“if X then Y” 的表达式,其中X和Y都是条件。在Where子句中,你可能想要一个像这样的条件, if:GetAll <> 1 then empno = :empno 。换句话说,如果名为:GetAll的绑定变量的值为1,你就要返回所有的行。但是如果:GetAll不是1,就仅仅返回empno等于绑定变量:empno所指定的那一行。表示这个逻辑的Where子句的代码可能这样写:
??? WHERE empno = CASE WHEN :GetAll <> 1 THEN :empno ELSE empno END

??? This logic works, but is a bit counterintuitive to me.? Why would you even want to check empno =
empno?? There are other problems with this kind of formulation as well.? If you need to check multiple
columns, then you’ll need multiple CASE statements.? Plus, if empno is null, this check will fail, or at the
very least give you a result you didn’t expect.
??? 这个逻辑是对的,但是我感觉不直观。你为什么要去检查empno=empno?还有另外的问题,如果你需要检查多列,你就需要多个CASE语句。甚者,如果empno是空,这个检查将失败,或者至少给你不期望的结果。
??? The key is to change this expression to use a regular Boolean expression that uses only AND, OR, and NOT so that your “if X then Y” condition is translated to “(Not X) or Y”.? This becomes:
???? WHERE (:GetAll = 1) OR (empno = :empno)

??? 改造这个表达式的关键是使用正规的布尔表达式,仅仅使用AND,OR和NOT。这样你的“if X then Y”就可以翻译成“(Not X) or Y”。这就成了:
??? WHERE (:GetAll = 1) OR (empno = :empno)

??? What you are covering with this expression is that if :GetAll = 1, then you don’t even want to
bother with checking any more of the expression.? Always remember that when using an OR condition, if one condition evaluates to TRUE, then the whole expression is TRUE.? There is no need to even check the remaining expression.? This “short-circuit” mechanism can save time by not requiring some of the code path to be evaluated.? That means you’ll not burn as many CPU cycles over all.? Only if the first condition that the optimizer chooses to test evaluates to FALSE would the other expression need to be evaluated.
??? 你用表达式if:GetAll = 1去覆盖, 然后你不希望更麻烦的去检查其他的表达式。永远记住当使用OR条件,如果一个条件评估成真,这个表达式为真。没有必要再去检查其他的表达式。这个“短路”机制,不需要评估一些代码路径,而节约时间。这意味着你完全可以让CPU少运转。只有优化器选择的第一个条件评估为FALSE才需要去评估其它的表达式。
??? Although you’re not looking at expressions involving ANDed conditions in these examples, you can
apply similar thinking to the use of ANDed predicates.? When using an AND condition, if the first condition evaluates to FALSE, then the whole expression is FALSE.? There is no need to evaluate the second expression since both conditions must evaluate to TRUE for the whole condition to be TRUE.? So, when you’re using AND conditions, it’s a good idea to write the condition so the expression that is most likely to evaluate to FALSE is placed first.? Doing so allows the second expression evaluation to be short-circuited with similar savings as noted when placing a TRUE expression first in an OR condition.
??? 尽管在这个例子中没有讨论涉及AND的条件表达式,你能应用相似的思维于AND谓词。当使用AND,如果第一个条件评估成FALSE,整个表达式是FALSE。没有必要去评估第二个表达式,因为两个条件都为TRUE时,整个表达式才是TRUE。如果你用AND条件,将最有可能评估是FALSE的表达式写在(整个表达式)最前面是个聪明的注意。这样做将允许第二个表达式被“短路”,类似于将TRUE表达式放在OR条件之前能节约时间。
??? A similar way of approaching this type of conditional expression is to use a single bind variable
instead of two.? In this case, you could say “if X is not null then Y = X”.? This becomes:
? ?? WHERE empno = NVL(:empno, empno)
?
??? This is basically the same as writing the CASE expression from the earlier example and could be
converted to:
???? WHERE (:empno is null) OR (empno = :empno)

??? 一种类似的方法完成这种条件表达式是使用单个绑定变量而非两个。在这个例子中,你可以说成是:“if X is not null then Y=X”。这就成了:
??? WHERE empno = NVL(:empno, empno)
???? 本质上同前面写的CASE表达式是一样的,也可以转成:
???? WHERE (:empno is null) OR (empno = :empno)

???? In both of these cases, the optimizer may have a bit of a dilemma with determining the optimal
plan.? The reason is that if the binds you use cause the comparison to end up returning all rows, then the plan operation best suited for that would likely be a full table scan.? However, if you specify binds that end up limiting the result set, an index scan might be best.? Since you’re using bind variables, each time you execute the query, the input bind values could change.? So, the optimizer has to choose a plan that will cover both situations. Most likely, you’ll end up with a full table scan.? Listing 5-5 demonstrates each of the scenarios I have covered and shows the execution plan output for each.
??? 上述两个例子中,优化器可能对于决定优化的执行计划有点放难。原因是,如果你所用的用于比较的绑定变量,最终返回的是所有行,最合适的执行计划操作应该是全表扫描。因为你使用了绑定变量,每次你执行查询,输入的绑定变量可能会改变。这样的话,优化器只能选择一种能照顾两种情况的执行计划。最有可能你最终得到的是全表扫描。列表5-5演示了我所论及的每种场景且显示了每个的执行计划输出。
Listing 5-5. Different Methods to Express Conditional Logic?
SQL> variable empno number
SQL> variable getall number
SQL>
SQL> exec :empno := 7369;
?
PL/SQL procedure successfully completed.
?
SQL>
SQL> exec :getall := 1;
?
PL/SQL procedure successfully completed.
?
SQL>
SQL> select /* opt1 */ empno, ename from emp?
? 2? where empno = CASE WHEN :GetAll <> 1 THEN :empno ELSE empno END;
?
????????? EMPNO ENAME
--------------- ----------
?????????? 7369 SMITH
?????????? 7499 ALLEN
?????????? 7521 WARD
?????????? 7566 JONES
?????????? 7654 MARTIN
?????????? 7698 BLAKE
?????????? 7782 CLARK
?????????? 7788 SCOTT
?????????? 7839 KING
?????????? 7844 TURNER
?????????? 7876 ADAMS
?????????? 7900 JAMES
?????????? 7902 FORD
?????????? 7934 MILLER
?
14 rows selected.
?
SQL>
SQL> @pln opt1
?
PLAN_TABLE_OUTPUT
---------------------------------------------------
SQL_ID? gwcmrzfqf8cu2, child number 0
-------------------------------------
select /* opt1 */ empno, ename from emp where empno = CASE WHEN :GetAll
<> 1 THEN :empno ELSE empno END
?
Plan hash value: 3956160932

-----------------------------------
| Id? | Operation??????????????????????????? | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------
|?? 0 | SELECT STATEMENT???????????? |?????????? |????? 1???? |?????? ? ? ? |???? 14 ? ?? |?????? 8 ? |
|*? 1 |? TABLE ACCESS FULL????????? | EMP? |????? 1???? |????? 1????? |???? 14????? |?????? 8?? |
-----------------------------------
?
Predicate Information (identified by operation id):
---------------------------------------------------
?
?? 1 - filter("EMPNO"=CASE? WHEN (:GETALL<>1) THEN :EMPNO ELSE "EMPNO" END )
?
?
19 rows selected.
?
SQL>
SQL> select /* opt2 */ empno, ename from emp?
? 2? where (:GetAll = 1) OR (empno = :empno);
?????????? EMPNO ENAME
--------------- ----------
?????????? 7369 SMITH
?????????? 7499 ALLEN
?????????? 7521 WARD
?????????? 7566 JONES
?????????? 7654 MARTIN
?????????? 7698 BLAKE
?????????? 7782 CLARK
?????????? 7788 SCOTT
?????????? 7839 KING
?????????? 7844 TURNER
?????????? 7876 ADAMS
?????????? 7900 JAMES
?????????? 7902 FORD
?????????? 7934 MILLER
14 rows selected.
SQL>
SQL> @pln opt2
PLAN_TABLE_OUTPUT
---------------------------------------------------
SQL_ID? 0yk6utwur2fbc, child number 0
-------------------------------------
select /* opt2 */ empno, ename from emp where (:GetAll = 1) OR (empno =
:empno)
?
Plan hash value: 3956160932
?
-----------------------------------
| Id? | Operation????????????????????????????? ? | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------
|?? 0 | SELECT STATEMENT???????? ? ? ?? |?????????? |????? 1??? |?????????????? |???? 14 ? ? |?????? 8 ?? |
|*? 1 |? TABLE ACCESS FULL???????????? | EMP? |????? 1??? |????? 1?????? |???? 14???? |?????? 8??? |
-----------------------------------
?
Predicate Information (identified by operation id):
---------------------------------------------------
?
?? 1 - filter(("EMPNO"=:EMPNO OR :GETALL=1))
19 rows selected.
SQL>
SQL> exec :getall := 0;
?
PL/SQL procedure successfully completed.
?
SQL>
SQL> select /* opt3 */ empno, ename from emp?
? 2? where empno = CASE WHEN :GetAll <> 1 THEN :empno ELSE empno END;
?
????????? EMPNO ENAME
--------------- ----------
?????????? 7369 SMITH
?
1 row selected.
?
SQL>
SQL> @pln opt3
?
PLAN_TABLE_OUTPUT
---------------------------------------------------
SQL_ID? bfmz26532svu1, child number 0
-------------------------------------
select /* opt3 */ empno, ename from emp where empno = CASE WHEN :GetAll
<> 1 THEN :empno ELSE empno END
?
Plan hash value: 3956160932
?
-----------------------------------
| Id? | Operation????????????????????????? | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------
|?? 0 | SELECT STATEMENT? ? ? ? ? ? |??????????? |????? 1 ? |?????? ? ? ? ? |????? 1?????? |?????? 8 ? |
|*? 1 |? TABLE ACCESS FULL???????? | EMP ?? |????? 1? |????? 1??????? |????? 1????? |?????? 8 ? |
-----------------------------------
?
Predicate Information (identified by operation id):
---------------------------------------------------
?
?? 1 - filter("EMPNO"=CASE? WHEN (:GETALL<>1) THEN :EMPNO ELSE "EMPNO" END )
?
?
19 rows selected.
?SQL>
SQL> select /* opt4 */ empno, ename from emp?
? 2? where (:GetAll = 1) OR (empno = :empno);
?
????????? EMPNO ENAME
--------------- ----------
?????????? 7369 SMITH
?
1 row selected.
?
SQL>
SQL> @pln opt4
?
PLAN_TABLE_OUTPUT
---------------------------------------------------
SQL_ID? aqp35x47gpphj, child number 0
-------------------------------------
select /* opt4 */ empno, ename from emp where (:GetAll = 1) OR (empno =
:empno)
?
Plan hash value: 3956160932
-----------------------------------
| Id? | Operation??????? ? ? ? ? ? ? | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------
|?? 0 | SELECT STATEMENT????? |?????????? |????? 1?? |?????? ? ? ?? |????? 1???? |?????? 8?? |
|*? 1 |? TABLE ACCESS FULL?? | EMP ?? |????? 1?? |????? 1 ? ? |????? 1 ? ?? |?????? 8 ? |
-----------------------------------
?
Predicate Information (identified by operation id):
---------------------------------------------------
?
?? 1 - filter(("EMPNO"=:EMPNO OR :GETALL=1))
?
?
19 rows selected.
?
SQL>
SQL> select /* opt5 */ empno, ename from emp?
? 2? where empno = NVL(:empno, empno);
?????????? EMPNO ENAME
--------------- ----------
?????????? 7369 SMITH
?
1 row selected.
?
SQL>
SQL> @pln opt5
?
PLAN_TABLE_OUTPUT
---------------------------------------------------
SQL_ID? 605p3gyjbw82b, child number 0
-------------------------------------
select /* opt5 */ empno, ename from emp where empno = NVL(:empno, empno)
?
Plan hash value: 1977813858
?
-------------------------------------------------
| Id? | Operation?????????????? ? ? ? ? ? ? ? ? ? ? ? ? ?? ???? | Name? ? | Starts | E-Rows | A-Rows | Buffers |
-------------------------------------------------
|?? 0 | SELECT STATEMENT???????????? ? ? ? ? ? ? ? ? ? |??????????? ?? |????? 1? |????? ? ? ? ? ? |????? 1?????? |?????? 2?? |
|?? 1 |? CONCATENATION???????????????????????????? ? ?? |????????????? ? |????? 1 |?????? ? ? ? ?? |????? 1????? ? |?????? 2??? |
|*? 2 |?? FILTER???????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? |??????????????? |????? 1 ? |???????????????? |????? 0????? |?????? 0?? |
|?? 3 |??? TABLE ACCESS BY INDEX ROWID?????? | EMP????? ? |????? 0?? |??? ? ? 14???? |????? 0 ? ?? |?????? 0?? |
|*? 4 |???? INDEX FULL SCAN???????????????????????? ?? | PK_EMP? |????? 0?? |?????? 14??? ? |????? 0 ? ? ? |?????? 0 ? |
|*? 5 |?? FILTER?????????????????????????????????????????????? |??????????????? |????? 1 ? |???????????????? |????? 1????? |?????? 2??? |
|?? 6 |??? TABLE ACCESS BY INDEX ROWID?????? | EMP?? ? ?? |????? 1?? |???? ? 1????? ? |????? 1?????? |?????? 2?? |
|*? 7 |???? INDEX UNIQUE SCAN??????????????????? ?? | PK_EMP? |????? 1?? |????? 1???????? |????? 1 ? ?? |?????? 1 ? |
-------------------------------------------------
?
Predicate Information (identified by operation id):
---------------------------------------------------
?
?? 2 - filter(:EMPNO IS NULL)
?? 4 - filter("EMPNO" IS NOT NULL)
?? 5 - filter(:EMPNO IS NOT NULL)
?? 7 - access("EMPNO"=:EMPNO)
?
?
27 rows selected.
SQL>
SQL> select /* opt6 */ empno, ename from emp
? 2? where (:empno is null) OR (:empno = empno);
?
????????? EMPNO ENAME
--------------- ----------
?????????? 7369 SMITH
?
1 row selected.
?
SQL>
SQL> @pln opt6
?
PLAN_TABLE_OUTPUT
------------------------------------------------
SQL_ID? gng6x7nrrrhy9, child number 0
-------------------------------------
select /* opt6 */ empno, ename from emp where (:empno is null) OR
(:empno = empno)
?
Plan hash value: 3956160932

?
-----------------------------------
| Id? | Operation???????????????????????????? | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------
|?? 0 | SELECT STATEMENT???????? |?????????? |????? 1??? |?????????????? |????? 1 ? ?? | ????? 8??? |
|*? 1 |? TABLE ACCESS FULL????? | EMP? |????? 1??? |????? 2??????? |????? 1????? |?????? 8??? |
-----------------------------------
?
Predicate Information (identified by operation id):
---------------------------------------------------
?
?? 1 - filter((:EMPNO IS NULL OR "EMPNO"=:EMPNO))
SQL>
SQL> exec :empno := null;
?
PL/SQL procedure successfully completed.
?
SQL>
SQL> select /* opt7 */ empno, ename from emp?
? 2? where empno = NVL(:empno, empno);
?????????? EMPNO ENAME
--------------- ----------
?????????? 7369 SMITH
?????????? 7499 ALLEN
?????????? 7521 WARD
?????????? 7566 JONES
?????????? 7654 MARTIN
?????????? 7698 BLAKE
?????????? 7782 CLARK
?????????? 7788 SCOTT
?????????? 7839 KING
?????????? 7844 TURNER
?????????? 7876 ADAMS
?????????? 7900 JAMES
?????????? 7902 FORD
?????????? 7934 MILLER
?
14 rows selected.
?
SQL>
SQL> @pln opt7
?
PLAN_TABLE_OUTPUT
---------------------------------------------------
SQL_ID? 83dydzdzbn5zh, child number 0
-------------------------------------
select /* opt7 */ empno, ename from emp where empno = NVL(:empno, empno)
?
Plan hash value: 1977813858
?
-------------------------------------------------
| Id? | Operation?????????????????????????????????? ? ? ? ? ? ? ? | Name? ? ?? | Starts | E-Rows | A-Rows | Buffers |
-------------------------------------------------
|?? 0 | SELECT STATEMENT???????????????????????? ? ? ? ?? |????? ? ? ????? |??? ? ? 1? |?????? ? ? ?? |???? 14 ? ?? |?????? 4??? |
|?? 1 |? CONCATENATION?????????????? ? ? ? ? ? ? ? ? ???? |?????? ? ? ? ? ? |????? 1 ?? |?????? ? ? ?? |???? 14????? |?????? 4??? |
|*? 2 |?? FILTER?????????????????????????????????? ? ? ? ? ? ? ?? |?????????????? ?? |????? 1 ?? |?????? ? ? ?? |???? 14???? |?????? 4??? |
|?? 3 |??? TABLE ACCESS BY INDEX ROWID?? ? ? ?? | EMP??????? ? |????? 1 ?? |???? 14???? |???? 14 ? ?? |?????? 4 ?? |
|*? 4 |???? INDEX FULL SCAN?????????????????????????? ? ? | PK_EMP??? |????? 1? ? |???? 14???? |???? 14????? |?????? 2 ?? |
|*? 5 |?? FILTER??????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |?????? ? ? ? ? ?? |????? 1? ? |?????? ? ? ?? |????? 0????? |?????? 0 ?? |
|?? 6 |??? TABLE ACCESS BY INDEX ROWID?? ? ? ?? | EMP?? ? ? ?? |????? 0 ?? |????? 1 ? ?? |????? 0????? |?????? 0??? |
|*? 7 |???? INDEX UNIQUE SCAN??????? ? ? ? ? ? ? ? ? ? | PK_EMP??? |????? 0? ? |????? 1????? |????? 0????? |?????? 0 ?? |
-------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
?
?? 2 - filter(:EMPNO IS NULL)
?? 4 - filter("EMPNO" IS NOT NULL)
?? 5 - filter(:EMPNO IS NOT NULL)
?? 7 - access("EMPNO"=:EMPNO)
?
?
27 rows selected.
?
SQL>
SQL> select /* opt8 */ empno, ename from emp
? 2? where (:empno is null) OR (:empno = empno);
????????? EMPNO ENAME
--------------- ----------
?????????? 7369 SMITH
?????????? 7499 ALLEN
?????????? 7521 WARD
?????????? 7566 JONES
?????????? 7654 MARTIN
?????????? 7698 BLAKE
?????????? 7782 CLARK
?????????? 7788 SCOTT
?????????? 7839 KING
?????????? 7844 TURNER
?????????? 7876 ADAMS
?????????? 7900 JAMES
?????????? 7902 FORD
?????????? 7934 MILLER
?
14 rows selected.
?
SQL>
SQL> @pln opt8

PLAN_TABLE_OUTPUT
-------------------------------------------------
SQL_ID? 4zvrcjd586tt6, child number 0
-------------------------------------
select /* opt8 */ empno, ename from emp where (:empno is null) OR
(:empno = empno)
Plan hash value: 3956160932
-----------------------------------
| Id? | Operation????????????????????????? | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------
|?? 0 | SELECT STATEMENT??????????? |???????????? |????? 1? |??????????????? |???? 14???? |?????? 8 ? ? |
|*? 1 |? TABLE ACCESS FULL???????? | EMP??? |????? 1? |????? 2??????? |???? 14 ? ? |?????? 8???? |
-----------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
?? 1 - filter((:EMPNO IS NULL OR "EMPNO"=:EMPNO))???

??? For the first two examples where there are two bind variables, you’ll notice that the optimizer
chooses a full table scan operation in both cases.? But, notice what happens when you use only a single variable in the second set of examples.? In the second case, the optimizer uses a CONCATENATION plan for the NVL predicate and full table scan for the Boolean expression.? The CONCATENATION plan is the best in this case as it will work such that when the bind variable is null, the plan will execute the INDEX FULL SCAN operation to get all the rows; when the bind variable is not null, the plan will execute the INDEX UNIQUE SCAN operation to get just the one row that is needed.? That way, both options use an optimal execution path.
??? 对于前两个例子,都使用了两个绑定变量。你将注意到优化器对两者都使用的全表扫描。但注意当你只使用单个变量在第二个例子中发生了什么。在第二个例子中,优化器对NVL谓词使用了连结(CONCATENATION)计划,对布尔表达式使用了全表扫描。连结(CONCATENATION)计划对于绑定变量为空的情况运行最佳,计划将执行全索引扫描(INDEX FULL SCAN)操作来获取所有的行。当绑定变量不是空,计划将执行唯一索引扫描(INDEX UNIQUE SCAN)操作取得需要的那一行。这样,两种情况使用了一个优化的执行计划。
??? In this case, the Boolean logic didn’t give you the best plan so it’s good to know several alternative
ways to formulate the predicate so you can work to achieve the best possible plan.? With that in mind,
you could actually have written the query as shown in Listing 5-6.
??? 在这种情况下,布尔逻辑没有给你最佳的执行计划。知道公式化谓词的几种替代方案才好。你就能从中挑选出可能最好的执行计划。本着这种原理,你实际上可以写出List5-6展现的查询。
Listing 5-6. Using a UNION ALL to Handle Conditional Logic??? 使用UNION ALL处理条件逻辑
SQL> select /* opt9 */ empno, ename from emp
? 2? where :empno is null
? 3? union all
? 4? select empno, ename from emp
? 5? where :empno = empno;
????????? EMPNO ENAME
--------------- ----------
?????????? 7369 SMITH
1 row selected.
SQL>
SQL> @pln opt9
?
PLAN_TABLE_OUTPUT
-----------------------------------------------
SQL_ID? ab0juatnpc5ug, child number 0
-------------------------------------
select /* opt9 */ empno, ename from emp where :empno is null union all
select empno, ename from emp where :empno = empno
?
Plan hash value: 2001993376
?
------------------------------------------------
| Id? | Operation?????????????????????????????????????????????? | Name???????? | Starts | E-Rows | A-Rows | Buffers |
------------------------------------------------
|?? 0 | SELECT STATEMENT??????????????????????????????? |?????????????????? ? |????? 1?? |?????????????? |????? 1?????? |?????? 2???? |
|?? 1 |? UNION-ALL??????????????????????????????????????????? |???????????????????? |????? 1??? |?????????????? |????? 1?????? |?????? 2???? |
|*? 2 |?? FILTER??????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? |???????????????????? |????? 1??? |?????????????? |????? 0?????? |?????? 0???? |
|?? 3 |??? TABLE ACCESS FULL???????????????????????? ?? | EMP?? ? ? ? ? ? |????? 0??? |???? 14? ? ? |????? 0??????? |?????? 0???? |
|?? 4 |?? TABLE ACCESS BY INDEX ROWID????????? | EMP?? ????????? | ???? 1??? |????? 1???? ? |????? 1 ? ? ? |?????? 2???? |
|*? 5 |??? INDEX UNIQUE SCAN????????????????????????? | PK_EMP??????? |????? 1?? |????? 1? ? ?? |????? 1 ? ? ? |?????? 1???? |
------------------------------------------------?
Predicate Information (identified by operation id):
---------------------------------------------------
?
?? 2 - filter(:EMPNO IS NULL)
?? 5 - access("EMPNO"=:EMPNO)

???? Similar to the CONCATENATION plan, in this case you get a plan where two separate sub-plans are
unioned together to get the result.? If the bind variable is null, you’ll get a full scan operation and will get all rows returned.? When the bind variable is not null, you’ll get the unique index scan and return only the one row needed.? The FILTER operation acts to determine if the first sub-plan should be executed or not.? Notice the predicate information section where step 2 shows filter(:EMPNO IS NULL) indicating that only if the bind is null will the operation actually happen.
??? 类似于连接(CONCATENATION)计划,你将获得一个由两个独立的子计划合并而成的计划返回结果。如果绑定变量是空,你将使用全扫描操作返回所有的行。当绑定变量不是空,你将使用唯一索引扫描返回唯一需要行。过滤器(FILTER)运算决定第一个子计划是否运行。注意谓词信息段第二部分显示filter(:EMPNO IS NULL) 指示出仅当绑定变量是空,操作才实际发生。
???? In general, you’ll find that the optimizer will be able to make better plan operation choices when AND conditions are used.? As covered earlier, this is because an OR condition means that there could be two different possible operations that could be used based on how the expression evaluates.? With an AND condition, it is more likely that only a single choice, or at least choices that are not opposite in nature, will be considered.? So, if you can figure out a way to formulate your predicates to use ANDed conditions solely, you may find that the SQL produces more efficient plans and even is easier to maintain.??
??? 一般情况下,你会发现当使用AND条件时,优化器将能做出较好的操作选择计划。如前所述,这是因为:基于表达式被评估的方式,一个OR条件意味着有可能有两个不同的操作被用到。而用一个AND条件,更有可能只有一种选择,或者至少直觉上不是对立的选择,被考虑。如果你能想出一种只用AND条件的方式公式化表达你的谓词,你可能发现SQL生成了更有效的执行计划且更容易维护。
???? Also, if you are writing SQL statements inside a larger code body, like in a PL/SQL procedure, use
conditional constructs in the language and don’t put that logic in the SQL.? The simpler you can make
your SQL, and the fewer conditions that have to be handled in the statement directly, the less complexity the optimizer will need to sort through to determine an optimal plan.
??? 还有,如果你在一大段的代码体中写SQL,如在PL/SQL过程中,用到了(PL/SQL)语言中的条件构造,不要将那些逻辑放到SQL中来。尽量让你的SQL简单,在语句中处理的条件越少,优化器需要挑选决定优化计划的复杂度就会越少。

?

Summary
??? Questions are an important part of the process of writing good SQL.? You begin by understanding the question the SQL needs to answer, then you follow up by asking questions about the data to formulate a SQL statement that is functionally correct as well as optimized for performance.? The ability to ask good questions is an intellectual habit that must be developed over time.? The more you work to ask questions that clarify and enhance your understanding of what you need to do, the greater your skills as a writer of high-quality, high-performing SQL will become.
总结
??? (提)问题是写出好SQL过程中的重要部分。开始时,你理解SQL需要回答的问题,然后你问关于数据的问题,用于公式化表达一个功能正确,而且性能优化的SQL语句。提问题的能力是一种个人习惯需要长时间的培养。澄清和增强理解,你需要做什么的问题,你问的越多,你写出高质量,高性能SQL的技能将变得越强。

1 楼 Branding 2012-02-17  
谢谢,获益匪浅
  相关解决方案