有限结果集

在Oracle 中。 使用好 ROWNUM 这个栏位, 将会非常实用。

一般来说能够用它来做两件事情:

1.  运行top-N的查询。这和其它数据库的 LIMIT 语法的作用相似。(查找前N笔数据)

2. 运行分页查询, 特别是在Web 这种无状态的环境。


ROWNUM 是怎样工作的

ROWNUM 是一个在查询中的虚列(不是实际的列)。

ROWNUM 的值是相似于: 1,,2,,3,4,...,N。ROWNUM 的值不是永久的分配给某行。所用不能使用 ROWNUM=5 这种方式来找到某行。

另一个重要的概念是ROWNUM什么时间被赋值。

ROWNUM 在某个Query语句通过查询谓词阶段之后可是在查询做不论什么排序和汇总之前。

相同。ROWNUM的值仅仅有在分配之后才干增长。

像下面这种语句就得不到数据。

select * 
from t
where ROWNUM > 1;

原因是: ROWNUM > 1对于第一行来说是不正确的。ROWNUM不能提前到2.  考虑使用下面方式:

select ..., ROWNUM
from t
where <where clause>
group by <columns>
having <having clause>
order by <columns>;

能够看成是下面顺序进行处理:

1.  FROM/WHERE 子句先行

2.  ROWNUM 是从FROM/WHERE子句中分配和递增给每个输出行。

3. SELECT 被应用

4. GROUP BY 被应用

5. HAVING 被应用

6. ORDER BY 被应用

这就是为什么下面方式进行Query 来处理ROWNUM 是会有问题的了:

select * 
from emp
where ROWNUM <= 5
order by sal desc;


这个语句会任意的找五笔数据,而不是薪资最高的五笔数据。

所以, 正确的做法应该是:

先排序, 然后再使用 rownum. 能够这样

select *
from
( select *
from emp
order by sal desc )
where ROWNUM <= 5;



查询前 n 条数据

对与一张数据量非常大(百万级甚至很多其它) 且每个记录的内容都比較大的表来说, 获取前 10条或是100条数据的方式能够是:

1. Query 出全部数据, 取前 n 条  order by

2.  使用内部表的方式, 结合ROWNUM, 相似

SELECT * FROM ( your_query_here ) WHERE ROWNUM <= N.

除了从DB 中取的比較少的数据外,这两种方式在性能上差异非常大, 差在什么地方呢?

先来看一下第一种方式的运行过程

1.  全表扫描

2.  对全部数据依据字段排序

3. 假设排序的内存不够的话,从硬盘扩展

4. 结合扩展的暂时内存取出前 n 条数据

5. 释放暂时内存。


而另外一种方式的过程就要简单得多

1. 全表扫描

2. 排序区先取n 条数据,   n 条之后的数据每笔和这n 条进行比对, 满足条件的话就替换。

也就是说, 排序区始终仅仅有n 条数据。 也就不会从硬盘扩展。


笔者在实际开发的过程中, 在 2000万笔数据的状况下,

不使用ROWNUM 简直就无法使用了。  使用ROWNUM 的状况系统响应时间在 10s 内。



看样例

建立一个 EMPLOYEE 的表, 并插入一些数据

CREATE TABLE EMPLOYEE(
EMPID varchar2(10),
EMPNAME varchar2(10),
SALARY varchar2(60)
);

insert into EMPLOYEE values('001','zhao','7300');
insert into EMPLOYEE values('002','qian','7400');
insert into EMPLOYEE values('003','sun','7500');
insert into EMPLOYEE values('004','li','7200');
insert into EMPLOYEE values('005','zhou','7100');
insert into EMPLOYEE values('006','wu','7000');
insert into EMPLOYEE values('007','zheng','6500');
insert into EMPLOYEE values('008','wang','6000');
insert into EMPLOYEE values('009','feng','6100');
insert into EMPLOYEE values('010','chen','6200');
insert into EMPLOYEE values('011','zhu','6300');
insert into EMPLOYEE values('012','wei','6400');
insert into EMPLOYEE values('013','jiang','6700');
insert into EMPLOYEE values('014','shen','6600');
insert into EMPLOYEE values('015','han','6800');
insert into EMPLOYEE values('016','yang','6900');


能够自行插入 800 笔数据左右。

( 数据量较少可能看不出效果)

1. 如今想查看薪资最高的五笔数据。

1)使用 :

select * from EMPLOYEE where ROWNUM <= 5 order by SALARY desc;

得到 :


2) select * from EMPLOYEE  order by SALARY desc;

结果全然不相同。 验证了以上部分的描写叙述。

正确的写法能够是:

select * from(
select * from EMPLOYEE order by SALARY desc) where ROWNUM <= 5 ;