转自:http://bbs.csdn.net/topics/370033478

对于Oracle中分页排序查询语句执行效率的比较分析
作者:lzgame
在工作中我们经常遇到需要在Oracle中进行分页、排序、查询的组合SQL语句,举例来说,通常我们会这样写:(假定表test中id是主键,并且id从1开始没有间断顺序排列)

1. SELECT * FROM (
      SELECT id,a1,a2,a3,a4,a5,a6,a7,a8,a9, ROWNUM AS rn FROM test
      WHERE a1 LIKE '%%' AND ROWNUM<=1000000
      ORDER BY id
    ) t2 WHERE  rn>=999990;

但是由于ROWNUM是一个伪列,Oracle会首先查询满足ROWNUM<=1000000条件的记录,然后再对得到的记录进行排序,这就导致我
们并不能获得期望的排序结果。本应得到id为999990-1000000,实际上却得到了一些无规律并令人困惑的id结果。于是我做了以下改进;

2. SELECT * FROM (
      SELECT id,a1,a2,a3,a4,a5,a6,a7,a8,a9, ROWNUM AS rn FROM (
        SELECT id,a1,a2,a3,a4,a5,a6,a7,a8,a9 FROM test
        WHERE a1 LIKE '%%'
        ORDER BY id
      ) t1 WHERE  ROWNUM<=1000000
    ) t2 WHERE  rn>=999990;

显然,通过经典的三层分页排序查询结构,我确实得到了想要的结果。但是在数据量很大的数据表中,由于需要首先取得排序后的全部数据集,导致了执行效率的极
速降低,直至无法忍受。为了提高性能,我在网上查阅了很多资料,其中有一种说法是:当排序条件使用的关键字是主键或索引,并在WHERE子句中先于
ROWNUM使用过该关键字时,我们就可以采用1号语句获得想要的结果了,于是我改写了1号语句并进行了测试:

3. SELECT * FROM (
      SELECT id,a1,a2,a3,a4,a5,a6,a7,a8,a9, ROWNUM AS rn FROM test
      WHERE id>=0 AND ROWNUM<=1000000
      ORDER BY id
    ) t2 WHERE  rn>=999990;

我惊喜的发现确实有效,我成功了,但惊喜并没有持续多久,因为当我把查询条件“a1 LIKE '%%'”也放回WHERE语句中时,一切又恢复了原状。
于是新一轮的资料查找又开始了。但网上的资料似乎始终没有脱离以上3种语句的范围,在漫长的查找后我快要放弃了,忽然在一条论坛回复中我看见了新的曙光:
用WHERE…IN语句。我立刻改写出了4号语句:

4.SELECT * FROM test 
   WHERE id IN (
      SELECT id FROM (
        SELECT id, ROWNUM AS rn FROM (
          SELECT id FROM test
          WHERE a1 LIKE '%%'
          ORDER BY id
        ) t1 WHERE  ROWNUM<=1000000
      ) t2 WHERE  rn>=999990 
    );

这条语句通过减少最内层SELECT语句获得的数据量(仅保留必须的id),极大地提高了查询性能。但是WHERE…IN语句由于需要遍历数据表,也就是
说在本语句中每查询出一个id,Oracle就需要在最后的WHERE…IN语句搜索一次并把它挑出来,所以WHERE…IN语句本身的效率并不高,本语
句依然存在着效率提升的空间,那么该怎么做呢?答案就是ROWID伪列。什么是ROWID伪列呢?用最简单的话说,ROWID就是该数据行的绝对物理地
址,在百度百科上我们可以查到索引就是通过ROWID来记录数据位置的。于是我们的WHERE…IN语句不再需要遍历数据表,不再需要通过一次次的检索来
收集数据了,因为它得到了最终数据的直接物理地址。从这个意义上讲,WHERE…IN语句成为了最高效的语句。
语句改写如下:

5.SELECT * FROM test 
   WHERE ROWID IN (
      SELECT rid FROM (
        SELECT rid, ROWNUM AS rn FROM (
          SELECT ROWID rid FROM test
          WHERE a1 LIKE '%%'
          ORDER BY id
        ) t1 WHERE  ROWNUM<=1000000
      ) t2 WHERE  rn>=999990 
    );

令人困惑的是,虽然5号语句检索出来的数据范围是正确的,但是最终的顺序是被打乱的,也就是说id虽然范围是在999990-1000000中,但相互间是没有顺序的,当然到这一步已经没有什么难度了,于是我写出了最终的语句:

6. SELECT * FROM test 
   WHERE ROWID IN (
      SELECT rid FROM (
        SELECT rid, ROWNUM AS rn FROM (
          SELECT ROWID rid FROM test
          WHERE a1 LIKE '%%'
          ORDER BY id
        ) t1 WHERE  ROWNUM<=1000000
      ) t2 WHERE  rn>=999990 
    ) ORDER BY id;
至此一切OK,为了对提升的效率有个直观的理解,我又对1、2、4、6号语句进行了测试(测试数据表test共1011003条记录),各测试三次去平均值,结果如下:

1号语句(两层嵌套,而且结果并不符合预期):21.98秒
2号语句(三层嵌套,结果符合预期,但实在是太慢了。。。):48.62秒
4号语句(采用WHERE id IN …,结果符合预期,效率极大提高):11.49秒
6号语句(采用WHERE ROWID IN …,结果符合预期,效率最高):5.98秒

以上是我对Oracle中分页排序查询语句执行效率的一点理解,如果有什么错误的地方请大家指正,谢谢!

对于Oracle中分页排序查询语句执行效率的比较分析的更多相关文章

  1. Oracle中的一些查询语句及其执行顺序

    查询条件: 1)LIKE:模糊查询,需要借助两个通配符,%:表示0到多个字符:_:标识单个字符. 2)IN(list):用来取出符合列表范围中的数据. 3)NOT IN(list): 取出不符合此列表 ...

  2. 常用oracle中系统表查询语句

    sqlplus / as sysdbaSQL>select status from v$instance;1.查看最大连接数show parameter processes;2.查询oracle ...

  3. Oracle中分页查询语句

    Oracle分页查询语句使我们最常用的语句之一,下面就为您介绍的Oracle分页查询语句的用法,如果您对此方面感兴趣的话,不妨一看. Oracle分页查询语句基本上可以按照本文给出的格式来进行套用.O ...

  4. Oracle rownum 分页, 排序

    Oracle rownum 分页, 排序 什么是rownum, rownum的生成, rownum相关的符号操作 Rownum是oracle生成结果集时得到的一个伪列, 按照读出行的顺序, 第一条ro ...

  5. oracle中分页函数写法

    1.常见的分页查询语句: 查询21到40条之间的数据:SELECT *FROM (select UI.*,ROWNUM RN FROM (select * from user_info) AWHERE ...

  6. SQL逻辑查询语句执行顺序 需要重新整理

    一.SQL语句定义顺序 1 2 3 4 5 6 7 8 9 10 SELECT DISTINCT <select_list> FROM <left_table> <joi ...

  7. python 3 mysql sql逻辑查询语句执行顺序

    python 3 mysql sql逻辑查询语句执行顺序 一 .SELECT语句关键字的定义顺序 SELECT DISTINCT <select_list> FROM <left_t ...

  8. mysql第四篇--SQL逻辑查询语句执行顺序

    mysql第四篇--SQL逻辑查询语句执行顺序 一.SQL语句定义顺序 SELECT DISTINCT <select_list> FROM <left_table> < ...

  9. MySQL查询语句执行过程及性能优化(JOIN/ORDER BY)-图

    http://blog.csdn.net/iefreer/article/details/12622097 MySQL查询语句执行过程及性能优化-查询过程及优化方法(JOIN/ORDER BY) 标签 ...

随机推荐

  1. git学习之remote

    修改远程仓库:$ git remote set-url --push [name] [newUrl] git pull 的时候报错 fatal: Authentication failed for ' ...

  2. 每日一词【命令行CMD】

    CURL 中文:命令行URL下载 英文解释:CommendLine Uniform Resource Locator 使用场景: 文件传输 curl是利用URL语法在命令行方式下工作的开源文件传输工具 ...

  3. 【CSS3】---:before :after生成内容

    在Web中插入内容,在CSS2.1时代依靠的是JavaScript来实现.但进入CSS3进代之后我们可以通过CSS3的伪类“:before”,“:after”和CSS3的伪元素“::before”.“ ...

  4. ruby学习--block

    #当前块 class Block def a_method return yield if block_given? 'no block' end end obj=Block.new puts &qu ...

  5. Ionic之顺带APP

    1:Ionic简介 官方:我们设计ionic来帮助 web 开发人员能够像开发网站一样开发出强大的移动APP应用. ionic是一个html5开发APP的框架,在开发运行效率可以说是最好的H5框架,把 ...

  6. 二维码zxing源码分析(一)camera部分

    首先,我们先把zxing的源代码给下载下来,这个网上有很多,我下载的是2.3的,不得不说这个谷歌提供的包包含的功能还是很全面的.     我把下载的包解压后,找到android文件夹,导入到ecpli ...

  7. WIN7系统操作快捷键

    轻松访问 按住右Shift八秒钟:启用或关闭筛选键 按左 Alt+左 Shift+PrntScrn(或 PrntScrn):启用或关闭高对比度 按左 Alt+左 Shift+Num Lock :启用或 ...

  8. git 基本使用

    简单几步操作让你在终端下用git实现文件的上传. 一.克隆项目    在工作中,常见的情景都是远程库已经建好了,需要大家把代码拉下来,共同协作开发.本文所有操作均在终端下进行.    //克隆一个本地 ...

  9. UI1_UINavigationController

    // // FourthViewController.h // UI1_UINavigationController // // Created by zhangxueming on 15/7/6. ...

  10. 7款震撼人心的HTML5CSS3文字特效

    1.HTML5像素文字爆炸重组动画特效 今天我们要分享一款基于HTML5技术的文字像素爆炸重组动画特效,我们可以在输入框中指定任意文字,点击确定按钮后,就会将原先的文字爆炸散去,新的文字以像素点的形式 ...