oracle分页查询不用order by排序速度反而变慢问题分析总结

--sql-1,不使用order by排序再分页,执行300多秒才出来:
select *
  from (select t.*, rownum rn
          from (select a.RFID,
                       decode(e.type, '112', e.name, sh.name) as name,
                       to_char(d.DEATH_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                       to_char(d.DEATH_DEAL_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                       d.DEATH_DEAL_TAG,
                       d.DEATH_TYPE,
                       to_char(d.DEATH_REG_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                       d.DEATH_DEAL_RESULT,
                       d.DEATH_REASON,
                       d.death_change,
                       d.death_method,
                       d.id /* ,
                            rownum as ro    */
                  from tbl_Death       d,
                       tbl_animal_info a,
                       tbl_Enterprise  e,
                       tbl_Enterprise  sh,
                       tbl_Region      r
                 where d.ANIMAL_ID = a.id
                   and a.ENTERPRISE_ID = e.id(+)
                   and a.owner_name = to_char(sh.id(+))
                   and e.REGION_ID = r.id
                   and r.code like '331082%'
                --order by d.id desc   
                ) t
         where rownum <= 20) re
 where re.rn >= 1


sql-1第一次执行了300多秒才出来,第二次17秒,第三次12秒。
sql-1执行计划:(可以看到cost消耗很小,cardinality基数很大)


--sql-2,使用order by排序再分页,1秒左右出来:
select *
  from (select t.*, rownum rn
          from (select a.RFID,
                       decode(e.type, '112', e.name, sh.name) as name,
                       to_char(d.DEATH_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                       to_char(d.DEATH_DEAL_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                       d.DEATH_DEAL_TAG,
                       d.DEATH_TYPE,
                       to_char(d.DEATH_REG_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                       d.DEATH_DEAL_RESULT,
                       d.DEATH_REASON,
                       d.death_change,
                       d.death_method,
                       d.id /* ,
                            rownum as ro    */
                  from tbl_Death       d,
                       tbl_animal_info a,
                       tbl_Enterprise  e,
                       tbl_Enterprise  sh,
                       tbl_Region      r
                 where d.ANIMAL_ID = a.id
                   and a.ENTERPRISE_ID = e.id(+)
                   and a.owner_name = to_char(sh.id(+))
                   and e.REGION_ID = r.id
                   and r.code like '331082%'
                 order by d.id desc) t
         where rownum <= 20) re
 where re.rn >= 1


sql-2第一次执行3.2秒,后面都是0.4秒内就出来了。
sql-2执行计划:(可以看到cost消耗较小,cardinality基数变很小了)



以前看执行计划,以为只要看cost消耗小,sql就会执行很快,现在看来cardinality基数的影响也是很大的。

--sql-3 是sql-1不分页,内层的sql,执行很快1秒内。
select a.RFID,
                       decode(e.type, '112', e.name, sh.name) as name,
                       to_char(d.DEATH_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                       to_char(d.DEATH_DEAL_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                       d.DEATH_DEAL_TAG,
                       d.DEATH_TYPE,
                       to_char(d.DEATH_REG_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                       d.DEATH_DEAL_RESULT,
                       d.DEATH_REASON,
                       d.death_change,
                       d.death_method,
                       d.id /* ,
                            rownum as ro    */
                  from tbl_Death       d,
                       tbl_animal_info a,
                       tbl_Enterprise  e,
                       tbl_Enterprise  sh,
                       tbl_Region      r
                 where d.ANIMAL_ID = a.id
                   and a.ENTERPRISE_ID = e.id(+)
                   and a.owner_name = to_char(sh.id(+))
                   and e.REGION_ID = r.id
                   and r.code like '331082%'


sql-3执行速度基本和sql-2一样。
sql-3执行计划:(可以看到cost消耗和cardinality基数,基本和排序了的sql-2在一个数量级)



总结分析:不用order by排序而分页,oracle需要耗费更多来记住这个无序的排序,以用以分页。而已经按索引列排序的字段order by后,减少了这个过程。所以使用order by反而加快了实际查询速度。

ps:有高手看到的话希望能提点一下:sql-1第一次执行300多秒,后面接着执行几次变成了10秒多出来,这是oracle的什么缓存机制吗?想知道具体是oracle的什么样的原理机制。这也是线上系统经常遇到的一个问题,第一次点sql执行太久,不出结果,过一会再点就可以了。

猜你喜欢

转载自jimmy9495.iteye.com/blog/1537981