开发人员说后台查询某业务数据明细,非常慢,让我优化下,
然后我到公司平台点击页面上的查询发现花了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返回数据了