【一学就会】Oracle通过伪列ROWNUM来实现分页功能

本人详解
作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》
公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题
中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯
转载说明:务必注明来源(注明:作者:王文峰哦)

在这里插入图片描述

学习教程(传送门)

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_idfirst_namelast_namedepartment_id等列。经常需要根据last_name进行查询。

优化前

SELECT * FROM employees WHERE last_name = 'Smith';

优化后

  1. last_name列上创建索引。
CREATE INDEX idx_last_name ON employees(last_name);
  1. 执行查询。
SELECT /*+ INDEX(employees idx_last_name) */ * FROM employees WHERE last_name = 'Smith';

(注意:在Oracle中,可以使用提示(hint)来强制查询使用特定的索引,但通常建议让Oracle优化器自行选择最佳执行计划。这里的示例仅用于演示如何指定索引。)

6、查询重写示例

场景:有一个名为orders的表,包含order_idcustomer_idorder_date等列。需要查询某个客户的所有订单,并且这些订单在某个日期之后。

优化前

SELECT * FROM orders WHERE customer_id = 123 AND order_date > TO_DATE('2023-01-01', 'YYYY-MM-DD');

优化后
如果customer_idorder_date列上已经有合适的索引,那么上面的查询已经足够高效。但是,如果查询条件经常变化,或者需要更复杂的过滤条件,可以考虑使用WITH子句(公用表表达式CTE)或临时表来简化查询。

不过,在这个特定场景中,更直接的优化可能是确保customer_idorder_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查询的速度和效率。在实际应用中,需要根据具体的场景和需求来选择合适的优化方法。

三、注意事项

  1. ROWNUM限制:ROWNUM只能在查询结果生成后分配,因此不能在WHERE子句中直接使用ROWNUM > n(n
  2. 0)这样的条件,需要使用子查询来间接实现。

  3. 性能优化:对于复杂的查询,可以考虑使用索引、优化查询语句等方式来提高性能。此外,对于分页查询的最后几页,采用HASH JOIN的方式可能更高效。
  4. 排序稳定性:当用来排序的列存在值相等的行时,可能会造成数据重复出现。为了避免这种情况,可以在排序时增加一个唯一标识列(如主键或ROWID)。

四、总结

Oracle分页查询是一种强大的数据检索方式,通过伪列ROWNUM和分页参数可以实现灵活的分页功能。在使用分页查询时,需要注意ROWNUM的限制、性能优化以及排序稳定性等问题。通过合理的设置和使用分页查询,可以方便地获取所需的数据并提高查询效率。

学习教程(传送门)

1、掌握 JAVA入门到进阶知识(持续写作中……
2、学会Oracle数据库用法(创作中……
3、手把手教你vbs脚本制作(完善中……
4、牛逼哄哄的 IDEA编程利器(编写中……
5、吐血整理的 面试技巧(更新中……
在这里插入图片描述

往期文章

 第一章:日常_JAVA_面试题集15(含答案)
 第二章:日常_JAVA_面试题集14(含答案)
平安壹钱包面试官:请你说一下Mybatis的实现原理
Java开发-热点-热门问题精华核心总结-推荐
 往期文章大全……
在这里插入图片描述

一键三连 一键三连 一键三连~
在这里插入图片描述

本人详解
作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》
公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题
中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯
转载说明:务必注明来源(注明:作者:王文峰哦)

一键三连 一键三连 一键三连~
以上就是今天的内容,关注我,不迷路