开发人员说后台查询某业务数据明细,非常慢,让我优化下,
然后我到公司平台点击页面上的查询发现花了6分钟,然后我把sql抓出来,发现是一个5个表关联的分页语句,
其中4个表只有几M,一个大表15G,小表就不用考虑了,然后我把大表拿出来单独分页查询发现同样花了6分钟,语句和执行计划如下:
SQL> explain plan for
2 SELECT *
FROM (SELECT t.*, rownum AS rn
FROM (SELECT *
FROM tb_recharge
WHERE create_date >= to_date(‘2014-09-01 00:00:00‘,‘yyyy-mm-dd hh24:mi:ss‘)
AND create_date < to_date(‘2014-10-01 00:00:00‘,‘yyyy-mm-dd hh24:mi:ss‘)
ORDER BY id desc) t
WHERE rownum <= 10
)
11 WHERE rn > 0
12 /
Explained.
Elapsed: 00:00:00.15
SQL> set lines 200 pages 200;
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4050647635
-------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name| Rows| Bytes | Cost (%CPU)| Time| Pstart| Pstop |
-------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT || 1 | 2047 | 1 (100)| 00:00:01 |||
|* 1 | VIEW || 1 | 2047 | 1 (100)| 00:00:01 |||
|* 2 | COUNT STOPKEY |||| ||||
| 3 | VIEW || 1 | 2034 | 1 (100)| 00:00:01 |||
|* 4 | SORT ORDER BY STOPKEY || 1 | 2034 | 1 (100)| 00:00:01 |||
| 5 | PARTITION RANGE SINGLE || 1 | 2034 | 0 (0)| 00:00:01 | 14 | 14 |
| 6 | TABLE ACCESS BY LOCAL INDEX ROWID| TB_RECHARGE| 1 | 2034 | 0 (0)| 00:00:01 | 14 | 14 |
|* 7 | INDEX RANGE SCAN | TB_RECHARGE_I5 | 1 || 0 (0)| 00:00:01 | 14 | 14 |
-------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("RN">0)
2 - filter(ROWNUM<=10)
4 - filter(ROWNUM<=10)
7 - access("CREATE_DATE">=TO_DATE(‘ 2014-09-01 00:00:00‘, ‘syyyy-mm-dd hh24:mi:ss‘) AND
"CREATE_DATE"<TO_DATE(‘ 2014-10-01 00:00:00‘, ‘syyyy-mm-dd hh24:mi:ss‘))
23 rows selected.
Elapsed: 00:00:05.38这个语句我把order by 去掉发现非常快ms级别返回数据,那么可以断定是order by导致性能问题,然后我count了一把发现数据600多万行,
注意sql中是按照create_date过滤,id排序,所以CBO根本就无法判断过滤后的数据id是否有序,
所以执行计划 4中出现了SORT ORDER BY STOPKEY,没有走first_rows特性,这一步对600多万行进行了order by,因此速度就慢在这了,
可想而知如果按照create_date排序那么就可以走fist_rows,然后我问开发人员是否可以按照时间字段排序,开发说不行,因为在同一时间会有很多数据,排序会混乱,那么就只能是用其它方法了
下面是我的解决方式:
在create_date,id 创建组合index,order by id 改写为ORDER BY create_date DESC, id DESC 创建index改写后的sql如下
SQL> explain plan for
2 SELECT *
FROM (SELECT t.*, rownum AS rn
FROM (SELECT /*+ index_desc(tb_recharge IDX_CREATEDATE_ID)*/*
FROM tb_recharge
WHERE create_date >= to_date(‘2014-09-01 00:00:00‘,‘yyyy-mm-dd hh24:mi:ss‘)
AND create_date < to_date(‘2014-10-01 00:00:00‘,‘yyyy-mm-dd hh24:mi:ss‘)
ORDER BY create_date DESC, id DESC ) t
WHERE rownum <= 10
)
11 WHERE rn > 0
12 /
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3687185489
---------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | |1 | 2047 |3 (67)| 00:00:01 | | |
|* 1 | VIEW | |1 | 2047 |3 (67)| 00:00:01 | | |
|* 2 | COUNT STOPKEY | | | | | | | |
| 3 | VIEW | |1 | 2034 |3 (67)| 00:00:01 | | |
| 4 | PARTITION RANGE SINGLE | |1 | 2034 |3 (67)| 00:00:01 | 14 | 14 |
| 5 | TABLE ACCESS BY LOCAL INDEX ROWID| TB_RECHARGE |1 | 2034 |3 (67)| 00:00:01 | 14 | 14 |
|* 6 | INDEX RANGE SCAN DESCENDING | IDX_CREATEDATE_ID |1 | | 71 (0)| 00:00:01 | 14 | 14 |
---------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("RN">0)
2 - filter(ROWNUM<=10)
6 - access("CREATE_DATE">=TO_DATE(‘ 2014-09-01 00:00:00‘, ‘syyyy-mm-dd hh24:mi:ss‘) AND "CREATE_DATE"<TO_DATE(‘
2014-10-01 00:00:00‘, ‘syyyy-mm-dd hh24:mi:ss‘))
21 rows selected.
Elapsed: 00:00:00.07优化后ms级别返回,看执行计划中SORT ORDER BY STOPKEY消失了,第6步中走了INDEX RANGE SCAN DESCENDING,如果是用高级执行计划可以看到cbo只访问了10行
就stop返回数据了
本文出自 “专注于Oracle性能调优” 博客,谢绝转载!
原文地址:http://5073392.blog.51cto.com/5063392/1568984