您的位置:首页 > 其它

sort order by导致分页语句性能问题优化

2014-10-28 19:59 453 查看
开发人员说后台查询某业务数据明细,非常慢,让我优化下,
然后我到公司平台点击页面上的查询发现花了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返回数据了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息