错误的转换绑定变量类型导致执行计划错误
2014-03-28 17:47
381 查看
昨天开发来问我个问题,一个业务sql执行缓慢,下面
SQL> SELECT A.ISSUE_OID,
(SELECT B.ISSUE_END_TIME FROM ISSUE_T B WHERE A.ISSUE_OID = B.IWOID) AS ISSUE_END_TIME,
(SELECT C.ENCASH_END_TIME FROM ISSUE_T C WHERE A.ISSUE_OID = C.IWOID) AS ENCASH_END_TIME,
A.OPERATOR_ID,
...
FROM SALE_DETAIL_T A
WHERE 1 = 1
AND A.TICKET_STATE = ?
AND A.SALE_TIME between ? and ?
......
SALE_DETAIL_T 数据600w,返回结果少量,SALE_TIME是索引列
带入参数,查看执行计划
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 187 | 3 (34)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 41 | 2 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 41 | 2 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 36 | 2 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 9 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 36 | 2 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 11 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 12 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 13 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 14 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 15 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 16 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 17 | HASH GROUP BY | | 1 | 187 | 3 (34)| 00:00:01 |
|* 18 | TABLE ACCESS BY INDEX ROWID| SALE_DETAIL_T | 1 | 187 | 2 (0)| 00:00:01 |
|* 19 | INDEX RANGE SCAN | SALE_DETAIL_SALE_TIME_IDX | 1 | | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("B"."IWOID"=:B1)
4 - access("C"."IWOID"=:B1)
6 - access("E"."IWOID"=:B1)
8 - access("D"."IWOID"=:B1)
10 - access("E"."IWOID"=:B1)
12 - access("F"."IWOID"=:B1)
14 - access("G"."IWOID"=:B1)
16 - access("H"."IWOID"=:B1)
18 - filter("A"."TICKET_STATE"=1)
19 - access("A"."SALE_TIME">=TO_DATE('2014-03-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss') AND
"A"."SALE_TIME"<=TO_DATE('2014-03-01 23:59:59', 'yyyy-mm-dd hh24:mi:ss'))
filter(SYS_OP_DESCEND("A"."SALE_TIME")<=HEXTORAW('878DFCFEF8FEF8FF') AND
SYS_OP_DESCEND("A"."SALE_TIME")>=HEXTORAW('878DFCFEE7C3C3FF') )
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
1419 bytes sent via SQL*Net to client
457 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
真实的执行计划如下
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 125 | 23375 | 101K (2)| 00:20:15 |
| 1 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 41 | 2 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 41 | 2 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 36 | 2 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 9 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 36 | 2 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 11 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 12 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 13 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 14 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 15 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 16 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 17 | HASH GROUP BY | | 125 | 23375 | 101K (2)| 00:20:15 |
|* 18 | FILTER | | | | | |
|* 19 | TABLE ACCESS FULL | SALE_DETAIL_T | 15932 | 2909K| 101K (2)| 00:20:15 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("B"."IWOID"=:B1)
4 - access("C"."IWOID"=:B1)
6 - access("E"."IWOID"=:B1)
8 - access("D"."IWOID"=:B1)
10 - access("E"."IWOID"=:B1)
12 - access("F"."IWOID"=:B1)
14 - access("G"."IWOID"=:B1)
16 - access("H"."IWOID"=:B1)
18 - filter(TO_TIMESTAMP('2014-03-01 00:00:00',:B1)<=TO_TIMESTAMP('2014-03-01
23:59:59',:B2))
19 - filter(INTERNAL_FUNCTION("A"."SALE_TIME")>=TO_TIMESTAMP('2014-03-01
00:00:00',:B1) AND INTERNAL_FUNCTION("A"."SALE_TIME")<=TO_TIMESTAMP('2014-03-01
23:59:59',:B2) AND "A"."TICKET_STATE"=1)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
455964 consistent gets
413600 physical reads
0 redo size
1419 bytes sent via SQL*Net to client
457 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
可以看到走了全表扫描,排查多种可能(也考虑到绑定变量窥探的情况,过程省略),结果很奇葩,原因是开发提交sql之前对绑定变量的类型使用的是to_timestamp方法,正确的应该用to_date转换争取的类型即可
SQL> SELECT A.ISSUE_OID,
(SELECT B.ISSUE_END_TIME FROM ISSUE_T B WHERE A.ISSUE_OID = B.IWOID) AS ISSUE_END_TIME,
(SELECT C.ENCASH_END_TIME FROM ISSUE_T C WHERE A.ISSUE_OID = C.IWOID) AS ENCASH_END_TIME,
A.OPERATOR_ID,
...
FROM SALE_DETAIL_T A
WHERE 1 = 1
AND A.TICKET_STATE = ?
AND A.SALE_TIME between ? and ?
......
SALE_DETAIL_T 数据600w,返回结果少量,SALE_TIME是索引列
带入参数,查看执行计划
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 187 | 3 (34)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 41 | 2 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 41 | 2 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 36 | 2 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 9 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 36 | 2 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 11 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 12 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 13 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 14 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 15 | TABLE ACCESS BY INDEX ROWID | ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 16 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 17 | HASH GROUP BY | | 1 | 187 | 3 (34)| 00:00:01 |
|* 18 | TABLE ACCESS BY INDEX ROWID| SALE_DETAIL_T | 1 | 187 | 2 (0)| 00:00:01 |
|* 19 | INDEX RANGE SCAN | SALE_DETAIL_SALE_TIME_IDX | 1 | | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("B"."IWOID"=:B1)
4 - access("C"."IWOID"=:B1)
6 - access("E"."IWOID"=:B1)
8 - access("D"."IWOID"=:B1)
10 - access("E"."IWOID"=:B1)
12 - access("F"."IWOID"=:B1)
14 - access("G"."IWOID"=:B1)
16 - access("H"."IWOID"=:B1)
18 - filter("A"."TICKET_STATE"=1)
19 - access("A"."SALE_TIME">=TO_DATE('2014-03-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss') AND
"A"."SALE_TIME"<=TO_DATE('2014-03-01 23:59:59', 'yyyy-mm-dd hh24:mi:ss'))
filter(SYS_OP_DESCEND("A"."SALE_TIME")<=HEXTORAW('878DFCFEF8FEF8FF') AND
SYS_OP_DESCEND("A"."SALE_TIME")>=HEXTORAW('878DFCFEE7C3C3FF') )
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
1419 bytes sent via SQL*Net to client
457 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
真实的执行计划如下
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 125 | 23375 | 101K (2)| 00:20:15 |
| 1 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 41 | 2 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 41 | 2 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 36 | 2 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 9 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 36 | 2 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 11 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 12 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 13 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 14 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 15 | TABLE ACCESS BY INDEX ROWID| ISSUE_T | 1 | 37 | 2 (0)| 00:00:01 |
|* 16 | INDEX UNIQUE SCAN | PK_ISSUE_T | 1 | | 1 (0)| 00:00:01 |
| 17 | HASH GROUP BY | | 125 | 23375 | 101K (2)| 00:20:15 |
|* 18 | FILTER | | | | | |
|* 19 | TABLE ACCESS FULL | SALE_DETAIL_T | 15932 | 2909K| 101K (2)| 00:20:15 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("B"."IWOID"=:B1)
4 - access("C"."IWOID"=:B1)
6 - access("E"."IWOID"=:B1)
8 - access("D"."IWOID"=:B1)
10 - access("E"."IWOID"=:B1)
12 - access("F"."IWOID"=:B1)
14 - access("G"."IWOID"=:B1)
16 - access("H"."IWOID"=:B1)
18 - filter(TO_TIMESTAMP('2014-03-01 00:00:00',:B1)<=TO_TIMESTAMP('2014-03-01
23:59:59',:B2))
19 - filter(INTERNAL_FUNCTION("A"."SALE_TIME")>=TO_TIMESTAMP('2014-03-01
00:00:00',:B1) AND INTERNAL_FUNCTION("A"."SALE_TIME")<=TO_TIMESTAMP('2014-03-01
23:59:59',:B2) AND "A"."TICKET_STATE"=1)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
455964 consistent gets
413600 physical reads
0 redo size
1419 bytes sent via SQL*Net to client
457 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
可以看到走了全表扫描,排查多种可能(也考虑到绑定变量窥探的情况,过程省略),结果很奇葩,原因是开发提交sql之前对绑定变量的类型使用的是to_timestamp方法,正确的应该用to_date转换争取的类型即可
相关文章推荐
- 不均衡分区和绑定变量窥视导致的查询计划错误
- 绑定变量导致执行计划不走索引
- 不均衡分区和绑定变量窥视导致的查询计划错误
- 通过重新生成执行计划解决绑定变量执行计划偏差导致SQL执行时间过长
- 类型转换导致执行计划不走索引测试案例
- 查看真实的执行计划 绑定变量对执行计划的影响--“绑定变量窥探”
- autotrace显示绑定变量执行计划不准确
- 统计信息自动收集时间窗口导致分区表执行计划错误
- 直方图统计导致错误的执行计划
- oracle 报Ora-01008错误:oracle 并非所有变量都已绑定的原因.TO_number();动态执行select..into..语句时
- 一个执行计划异常变更的案例 - 外传之绑定变量窥探
- 如何解决绑定变量造成执行计划不准的问题?
- 也谈SQL Server 2008 处理隐式数据类型转换在执行计划中的增强 (续)
- 使用to_number,to_char转换的连接列易造成错误的执行计划
- ORACLE绑定变量隐式转换导致性能问题
- 绑定变量窥探(bind peeking)--什么使执行计划不准
- ListView的Adapter有多个ViewHolder的时候导致的ViewHolder类型转换错误!
- sql执行计划[Oracle] 变量绑定
- 绑定变量与执行计划的“陷阱”
- 直方图统计导致错误的执行计划