概述
解析是什么意思呢? 就是分析的意思。
解析函数就是指能够完成某种复杂分析的函数,如求行号、求名次。这些函数可以拿来直接使用就可以完成复杂的分析任务。
首先学习Oracle解析函数的通用语法。先学习最简单的语法。
语法一:
解析函数() over(order by 字段 [desc])
说明:
over,英文意思就是“在……之上”。上面的语法整个意思就是指:“在排序的基础之上”进行的某种分析。
果解析函数是row_number()——行号,则表示是在某个字段排序的基础之上再求行号。
如果解析函数是rank()——名次,则表示是在某个字段排序的基础之上再求名次。
示例一:根据工资降序排序,显示行号及员工信息。
select row_number() over(order by sal desc) as 行号,
empno,ename,sal
from emp;
返回:
行号 EMPNO ENAME SAL
1 7839 KING 5000.00
2 7902 FORD 3000.00
3 7566 JONES 2975.00
……
对比使用rownum来得行号的sql语句:
select rownum as 行号,t.*
from (select empno,ename,sal from emp order by sal desc ) t
发现使用row_number()会没有使用嵌套子查询。
示例二:根据工资降序排序,并显示第4行到第6行的员工信息。
分析:
需要先在子查询中产生行号,然后再对行号进行过滤。
select * from (
select empno,ename,sal,
row_number() over(order by sal desc) as 行号
from emp
) t
where t.行号 between 4 and 6
对比使用rownum来得行号的sql语句:
select * from (
select rownum as 行号,t.*
from (select empno,ename,sal from emp order by sal desc ) t
)
where t.行号 between 4 and 6
使用row_number()最大的原因并不是因为少写了一层子查询,而是因为数据量比较大的时候,如上千万条记录,分页的效率非常高。
测试案例
--目标:产生上千万的模拟数据
create sequence my_seq;
create table emp2
as
select my_seq.nextval as empno, ename, job, mgr, hiredate, sal, comm, deptno
from emp;
--反复复制自身数据
insert into emp2
select my_seq.nextval as empno, ename, job, mgr, hiredate, sal, comm, deptno
from emp2;
commit;
至少产生1千万条记录以后再继续后面的操作。
问题:为什么下面的sql执行很慢?
select count(*) from emp2;
分析:因为emp2是通过复制表得到的,没有主键索引。所以count(*)是查询的原始表emp2,而emp2表中的数据量非常大。
解决:在emp2表上建立主键。
alter table EMP2 add constraint pk_emp2 primary key (EMPNO);
解释:修改emp2表,增加一个名称为“pk_emp2”约束,类型为主键,主键字段是empno。
“pk_emp2”是一个自定义名称,其中“pk”是主键的简称,通常后面跟表名。
说明:这种alter语句可以直接利用在PLSQL Developer工具的操作来得到,不需要死记。
现在执行count(*),时间就会非常快了。
对比下面两种sql运行的时间:
·根据empno降序排序,分别使用rownum和row_number()分页,取第2页,每页100条。
代码参考:
--使用rownum
SELECT *
FROM (SELECT ROWNUM NO, t.*
FROM (SELECT * FROM emp2 ORDER BY empno DESC) t)
WHERE NO BETWEEN 101 AND 200;
说明:应该是几十秒到上百秒。
--使用row_number()
select * from
(
select row_number() over(order by empno desc) 行号,
empno,ename,sal from emp2
) a
where a.行号 between 101 and 200
说明:正常情况下应该不到1秒。
大数据量高效分页小结
1、要在排序的字段上建立索引
2、使用Oracle解析函数:row_number()
对比试验:
删除主键约束pk_emp2,对应的索引也会被删除。再记录程序的运行时间。
alter table EMP2
drop constraint PK_EMP cascade;
说明:没有了索引,row_number的效率会降低非常多。
问题:row_number好像越到后面会越慢?
回答:
是的。如执行下面的SQL语句:
select * from
(
select row_number() over(order by empno desc) 行号,
empno,ename,sal from emp2
) a
where a.行号 between 10000000 and 10000100
执行:50秒左右(具体的时间与机器配置有关)
分析:实际上,分页以后最关心的数据就是放在最前面,
分页以后取到后面上万页的情况也不是很实际。
这也是我所体会到Oracle是最聪明的数据库之一:用户关心的数据,查询就快!
说明:
·在真正的分页程序中,必须指定排序的字段,记录的前后顺序才能确定下来。
·所以分页之前必须指定先按哪个字段来排序。