日期:2014-05-17  浏览次数:20895 次

SQL 调优问题,“占位操作” "开关操作 "
《DBA日记 第一部》中看 到这么一段话 

占位操作:占位操作是开发人员常用的一种编程方法,比如 WHERE 条件是动态生成的,那么WHERE
后面的第一个条件和后面的条件是不同的,WHERE 后面的第一个条件前面没有任何运算符,而后面的
都带有运算符,因此如果WHERE 变为WHERE 1=1 那么后面的所有条件都有运算符,编程就简单很多。

实际上占位操作是一种很不好的编程习惯,如果条件很复杂,大量使用占位操作,那么会导致优化器无
法获得正确的执行计划

开关操作:开关操作也是一种编程人员常用的编程手段,同样也是性能杀手。比如写好一个SQL 模板,
其中有一个开关(1=:p1 and ....),如果我们希望后面的AND 起作用,那么p1 就赋值为1,如果不希望
后面的AND 起作用,p1 就赋值非1 的值。


这个 “占位操作” "开关操作 "

能否有 达人 写两个语句 来说明一下??

------解决方案--------------------
例如,以下的SQL实现一个功能,
当输入参数是P的时候,使用索引的方式扫描表,
当输入参数是A的时候,使用全表扫描。

以下分析一下,这段SQL的执行计划和实际执行的行源操作
EXPLAIN PLAN FOR
SELECT * 
FROM test_738_a a
 WHERE DECODE(:p_mode, 'P', 1, 2) = 1
AND a.created >= SYSDATE -1
AND a.created < SYSDATE
UNION ALL
SELECT * 
FROM test_738_a a
 WHERE DECODE(:p_mode, 'P', 1, 2) = 2;
SELECT * FROM TABLE(dbms_xplan.display(NULL, NULL, 'ALL'));

-------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
-------------------------------------------------
| 0 | SELECT STATEMENT | | 356K| 31M| 1377 (100)|
| 1 | UNION-ALL | | | | |
|* 2 | FILTER | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| TEST_738_A | 19 | 1786 | 4 (0)|
|* 4 | INDEX RANGE SCAN | TEST_738_A_IND | 19 | | 3 (0)|
|* 5 | FILTER | | | | |
| 6 | TABLE ACCESS FULL | TEST_738_A | 356K| 31M| 1373 (1)|
-------------------------------------------------

你能看到这时候,这段执行计划的成本是很高的。

使用'P'参数,带入实际运行后,从trace文件中取得行源操作信息。
SELECT * 
FROM
 TEST_738_A A WHERE DECODE(:B1 , 'P', 1, 2) = 1 AND A.CREATED >= SYSDATE -1 
AND A.CREATED < SYSDATE UNION ALL SELECT * FROM TEST_738_A A WHERE 
DECODE(:B1 , 'P', 1, 2) = 2


call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 19.66 0 0 0 0
Execute 1 100.00 33.53 0 0 0 0
Fetch 1 100.00 247.35 6 15 0 43
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 3 200.00 300.54 6 15 0 43

Misses in library cache during parse: 1
Optimizer goal: ALL_ROWS
Parsing user id: 44 (recursive depth: 1)

Rows Row Source Operation
------- ---------------------------------------------------
43 UNION-ALL (cr=15 pr=6 pw=0 time=2258 us)
43 FILTER (cr=15 pr=6 pw=0 time=2207 us)
43 TABLE ACCESS BY INDEX ROWID TEST_738_A (cr=15 pr=6 pw=0 time=2147 us)
43 INDEX RANGE SCAN TEST_738_A_IND (cr=3 pr=3 pw=0 time=1811 us)(object id 770511)
0 FILTER (cr=0 pr=0 pw=0 time=4 us)
0 TABLE ACCESS FULL TEST_738_A (cr=0 pr=0 pw=0 time=0 us)

********************************************************************************
你能发现,只有索引部分的那段SQL被执行了。

使用'A'参数,带入实际运行后,从trace文件中取得行源操作信息。
SELECT * 
FROM
 TEST_738_A A WHERE DECODE(:B1 , 'P', 1, 2) = 1 AND A.CREATED >= SYSDATE -1 
AND A.CREATED < SYSDATE UNION ALL SELECT * FROM TEST_738_A A WHERE 
DECODE(:B1 , 'P', 1, 2) = 2