本人详解
作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》
公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题
中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯
转载说明:务必注明来源(注明:作者:王文峰哦)
【一学就会】Oracle通过伪列ROWNUM来实现分页功能
学习教程(传送门)
1、掌握 JAVA入门到进阶知识(持续写作中……)
2、学会Oracle数据库用法(创作中……)
3、手把手教你vbs脚本制作(完善中……)
4、牛逼哄哄的 IDEA编程利器(编写中……)
5、吐血整理的 面试技巧(更新中……)
【一学就会】Oracle通过伪列ROWNUM来实现分页功能
一、分页查询简介
在Oracle数据库中,分页查询是一种常用的数据检索方式,允许用户按照指定的页数和每页显示的行数来获取特定的数据。Oracle通过伪列ROWNUM来实现分页功能,ROWNUM为查询结果的每一行分配一个唯一的行号,基于这些行号可以实现分页查询。
二、分页查询实现步骤
1. 准备基础查询
首先,需要编写一个基本的查询语句来获取所有的数据,这个查询语句将作为分页查询的内层查询。
SELECT * FROM 表名;
2. 使用ROWNUM分配行号
在基础查询的基础上,使用ROWNUM为每一行分配一个唯一的行号。这个步骤通常作为分页查询的中间层查询。
SELECT mt1.*, ROWNUM AS rn FROM (基础查询) mt1;
3. 筛选特定行号范围
在外部查询中,使用WHERE子句来筛选出特定的行号范围,以实现分页查询。这里的行号范围由分页参数决定,如每页的起始行号和结束行号。
SELECT * FROM (中间层查询) WHERE rn BETWEEN :start_row AND :end_row;
其中,:start_row
和:end_row
是分页参数,分别表示每页的起始行号和结束行号。
4. 设置分页参数和计算总页数
为了实现更好的分页体验,通常需要设置分页参数并计算总页数。分页参数包括每页显示的行数(:page_size
)和当前页码(:page_number
)。总页数可以通过总行数除以每页显示的行数并向上取整来计算。
-- 计算总行数
SELECT COUNT(*) AS total_rows FROM 表名;
-- 计算总页数
SELECT CEIL(COUNT(*) / :page_size) AS total_pages FROM 表名;
5. 完整的分页查询示例
以下是一个完整的分页查询示例,展示了如何在Oracle中实现分页查询:
-- 设置分页参数
:page_number := 1; -- 当前页码
:page_size := 10; -- 每页显示的行数
:start_row := (:page_number - 1) * :page_size + 1;
:end_row := :page_number * :page_size;
-- 执行分页查询
SELECT * FROM (
SELECT e.*, ROWNUM AS rn FROM (
SELECT * FROM employees ORDER BY employee_id
) e
) WHERE rn BETWEEN :start_row AND :end_row;
-- 计算总行数和总页数(可选)
SELECT COUNT(*) AS total_rows, CEIL(COUNT(*) / :page_size) AS total_pages FROM employees;
在上面的示例中,我们首先设置了分页参数:page_number
和:page_size
,然后计算出:start_row
和:end_row
。接着,我们执行了分页查询,并可选地计算了总行数和总页数。
当然,以下是一些具体的Oracle查询优化示例,包括索引优化、查询重写、分页查询优化等方面的内容:
5、索引优化示例
场景:有一个名为employees
的表,包含employee_id
、first_name
、last_name
、department_id
等列。经常需要根据last_name
进行查询。
优化前:
SELECT * FROM employees WHERE last_name = 'Smith';
优化后:
- 在
last_name
列上创建索引。
CREATE INDEX idx_last_name ON employees(last_name);
- 执行查询。
SELECT /*+ INDEX(employees idx_last_name) */ * FROM employees WHERE last_name = 'Smith';
(注意:在Oracle中,可以使用提示(hint)来强制查询使用特定的索引,但通常建议让Oracle优化器自行选择最佳执行计划。这里的示例仅用于演示如何指定索引。)
6、查询重写示例
场景:有一个名为orders
的表,包含order_id
、customer_id
、order_date
等列。需要查询某个客户的所有订单,并且这些订单在某个日期之后。
优化前:
SELECT * FROM orders WHERE customer_id = 123 AND order_date > TO_DATE('2023-01-01', 'YYYY-MM-DD');
优化后:
如果customer_id
和order_date
列上已经有合适的索引,那么上面的查询已经足够高效。但是,如果查询条件经常变化,或者需要更复杂的过滤条件,可以考虑使用WITH子句(公用表表达式CTE)或临时表来简化查询。
不过,在这个特定场景中,更直接的优化可能是确保customer_id
和order_date
列上有联合索引(如果查询经常同时涉及这两个条件)。
-- 创建联合索引(如果尚未创建)
CREATE INDEX idx_customer_order_date ON orders(customer_id, order_date);
-- 执行查询(无需重写,因为索引已经优化)
SELECT * FROM orders WHERE customer_id = 123 AND order_date > TO_DATE('2023-01-01', 'YYYY-MM-DD');
7、分页查询优化示例
场景:有一个名为products
的表,包含大量产品记录。需要分页显示这些记录。
优化前(使用ROWNUM,适用于Oracle 12c之前):
SELECT * FROM (
SELECT a.*, ROWNUM rnum FROM (
SELECT * FROM products ORDER BY product_name
) a WHERE ROWNUM <= :endRow
) WHERE rnum >= :startRow;
其中,:startRow
和:endRow
是分页参数。
优化后(使用OFFSET和FETCH,适用于Oracle 12c及更高版本):
SELECT * FROM products ORDER BY product_name OFFSET :offsetRows ROWS FETCH NEXT :fetchRows ROWS ONLY;
其中,:offsetRows
表示要跳过的行数(即(pageNumber - 1) * pageSize
),:fetchRows
表示要返回的行数(即pageSize
)。
注意:对于大数据量的表,分页查询可能会变得非常慢,特别是当OFFSET
值很大时。在这种情况下,可以考虑使用基于索引的分页方法(如基于主键或唯一索引列的分页),或者对表进行分区。
定期维护索引:
- 可以使用Oracle的
DBMS_STATS
包来收集表和索引的统计信息,帮助优化器做出更好的决策。 - 定期检查索引的碎片情况,并考虑重建或重组索引。
监控查询性能:
- 使用Oracle的AWR(Automatic Workload Repository)报告来分析数据库的性能瓶颈。
- 监控SQL语句的执行时间和资源消耗,找出性能较差的查询并进行优化。
这些示例展示了如何通过索引优化、查询重写、分页查询优化以及实践建议来提高Oracle查询的速度和效率。在实际应用中,需要根据具体的场景和需求来选择合适的优化方法。
三、注意事项
- ROWNUM限制:ROWNUM只能在查询结果生成后分配,因此不能在WHERE子句中直接使用ROWNUM > n(n
-
0)这样的条件,需要使用子查询来间接实现。
- 性能优化:对于复杂的查询,可以考虑使用索引、优化查询语句等方式来提高性能。此外,对于分页查询的最后几页,采用HASH JOIN的方式可能更高效。
- 排序稳定性:当用来排序的列存在值相等的行时,可能会造成数据重复出现。为了避免这种情况,可以在排序时增加一个唯一标识列(如主键或ROWID)。
四、总结
Oracle分页查询是一种强大的数据检索方式,通过伪列ROWNUM和分页参数可以实现灵活的分页功能。在使用分页查询时,需要注意ROWNUM的限制、性能优化以及排序稳定性等问题。通过合理的设置和使用分页查询,可以方便地获取所需的数据并提高查询效率。
学习教程(传送门)
1、掌握 JAVA入门到进阶知识(持续写作中……)
2、学会Oracle数据库用法(创作中……)
3、手把手教你vbs脚本制作(完善中……)
4、牛逼哄哄的 IDEA编程利器(编写中……)
5、吐血整理的 面试技巧(更新中……)
往期文章
第一章:日常_JAVA_面试题集15(含答案)
第二章:日常_JAVA_面试题集14(含答案)
平安壹钱包面试官:请你说一下Mybatis的实现原理
Java开发-热点-热门问题精华核心总结-推荐
往期文章大全……
一键三连 一键三连 一键三连~
本人详解
作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》
公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题
中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯
转载说明:务必注明来源(注明:作者:王文峰哦)
一键三连 一键三连 一键三连~
以上就是今天的内容,关注我,不迷路