oracle分页并排序sql,一个分页排序SQL查询结果集不确定的案例

前几天一位运价的兄弟提出一个关于分页排序SQL的问题,比较有意思,这里分享一下。

前些日子碰巧看了杨长老这篇文章:《让SQL成为一种生活方式:认识分页查询》,以下为原文摘要:

Oracle的分页查询语句有两种基本格式。第一种格式如下:

select * from

(

select a.*, rownum rn

from (select * from table_name) a

where rownum <= 30

)

where rn>=21;

上面给出的这个分页查询语句,在大多数情况拥有较高的效率。其中最内层的查询SELECT * FROM TABLE_NAME表示不进行翻页的原始查询语句。ROWNUM<= 40和RN >= 21控制分页查询的每页的范围。

第二种方式是去掉查询第二层的WHERE ROWNUM <= 30语句,在查询的最外层控制分页的最小值和最大值。语法如下: “`

select * from

(

select a.*, rownum rn

from (select * from table_name) a

)

where rn between 21 and 30;

对比这两种写法,绝大多数的情况下,第一个查询的效率比第二个高得多。这是由于CBO优化模式下,Oracle可以将外层的查询条件推到内层查询中,以提高内层查询的执行效率。

对于第一个查询语句,第二层的查询条件WHERE ROWNUM <=

30就可以被Oracle推入到内层查询中,这样Oracle查询的结果一旦超过了ROWNUM限制条件,就终止查询将结果返回了。而第二个查询语句,由于查询条件BETWEEN

21 AND

30是存在于查询的第三层,而Oracle无法将第三层的查询条件推到最内层(即使推到最内层也没有意义,因为最内层查询不知道RN代表什么)。因此,对于第二个查询语句,Oracle最内层返回给中间层的是所有满足条件的数据,而中间层返回给最外层的也是所有数据。数据的过滤在最外层完成,显然这个效率要比第一个查询低得多。

同事提出的这条SQL,正是使用了上面提到的第一种写法。以下是叙述的信息,其中SQL做了脱敏,不影响原义。

第一条SQL是不带分页的查询语句,结果集中有一条CLS_CODE是B。

(此处原文有一些限定条件,确保第一条SQL的结果集肯定包含第二条和第三条的结果集,即CLS_CODE=B应该只有一条记录在第二条或第三条SQL的结果集中。)

SELECT T.C_CODE, (CASE T.FLG WHEN 'C' THEN 0 WHEN 'A' THEN 1 END) AS FLG FROM TABLE T LEFT JOIN RULE R ON TRIM(R.CODE) = 'PUB' AND R.NO = T.FILE_NO AND R._REC_NO = T.NO WHERE T.CODE = 'CA' AND T.D_DATE >= to_Date('2016-08-10 23:59:59','yyyy-mm-dd hh24:mi:ss') AND T.FIRST_DATE >= to_Date('2016-08-10 00:0

你可能感兴趣的:(oracle分页并排序sql)