oracle分页

分页查询格式:
SELECT * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
WHERE ROWNUM <= 40
)
WHERE RN >= 21
其中最内层的查询SELECT * FROM TABLE_NAME表示不进行翻页的原始查询语句。ROWNUM <= 40和RN >= 21控制分页查询的每页的范围。
上面给出的这个分页查询语句,在大多数情况拥有较高的效率。分页的目的就是控制输出结果集大小,将结果尽快的返回。在上面的分页查询语句中,这种考虑主要体现在WHERE ROWNUM <= 40这句上。
选择第21到40条记录存在两种方法,一种是上面例子中展示的在查询的第二层通过ROWNUM <= 40来控制最大值,在查询的最外层控制最小值。而另一种方式是去掉查询第二层的WHERE ROWNUM <= 40语句,在查询的最外层控制分页的最小值和最大值。这是,查询语句如下:
SELECT * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
)
WHERE RN BETWEEN 21 AND 40
对比这两种写法,绝大多数的情况下,第一个查询的效率比第二个高得多。
这是由于CBO优化模式下,Oracle可以将外层的查询条件推到内层查询中,以提高内层查询的执行效率。对于第一个查询语句,第二层的查询条件WHERE ROWNUM <= 40就可以被Oracle推入到内层查询中,这样Oracle查询的结果一旦超过了ROWNUM限制条件,就终止查询将结果返回了。
而第二个查询语句,由于查询条件BETWEEN 21 AND 40是存在于查询的第三层,而Oracle无法将第三层的查询条件推到最内层(即使推到最内层也没有意义,因为最内层查询不知道RN代表什么)。因此,对于第二个查询语句,Oracle最内层返回给中间层的是所有满足条件的数据,而中间层返回给最外层的也是所有数据。数据的过滤在最外层完成,显然这个效率要比第一个查询低得多。
上面分析的查询不仅仅是针对单表的简单查询,对于最内层查询是复杂的多表联合查询或最内层查询包含排序的情况一样有效。
这里就不对包含排序的查询进行说明了,下一篇文章会通过例子来详细说明。下面简单讨论一下多表联合的情况。对于最常见的等值表连接查询,CBO一般可能会采用两种连接方式NESTED LOOP和HASH JOIN(MERGE JOIN效率比HASH JOIN效率低,一般CBO不会考虑)。在这里,由于使用了分页,因此指定了一个返回的最大记录数,NESTED LOOP在返回记录数超过最大值时可以马上停止并将结果返回给中间层,而HASH JOIN必须处理完所有结果集(MERGE JOIN也是)。那么在大部分的情况下,对于分页查询选择NESTED LOOP作为查询的连接方法具有较高的效率(分页查询的时候绝大部分的情况是查询前几页的数据,越靠后面的页数访问几率越小)。
因此,如果不介意在系统中使用HINT的话,可以将分页的查询语句改写为:
SELECT /*+ FIRST_ROWS */ * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
WHERE ROWNUM <= 40
)
WHERE RN >= 21

以下是我的一个测试小例子
<%@ page language="java" import="java.sql.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>

<title>oracle分页原理</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>

<body>
<table>
<tr>
<td>
name
</td>
<td>
sal
</td>
</tr>

<%
String s_pageNo = request.getParameter("pageNo");
int pageNo = 1; //返回当前页数,默认为第一页
int rowCount = 0; //记录条数
int pageSize = 5; //每页显示条数
int pageCount = 0; //页数
if(s_pageNo != null){
pageNo = Integer.parseInt(s_pageNo);
}
Connection conn = null;
Statement st = null;
ResultSet rs = null;
String url = "jdbc:oracle:thin:@localhost:1521:数据库名";
String username = "scott";
String password = "tiger";
String sql = "select * from (select A.*,rownum rn from (select * from emp) A where rownum <= "+pageNo*pageSize+") where rn>="+((pageNo-1)*pageSize+1)+"";
String sql2 = "select * from (select A.*,rownum rn from (select * from emp) A where rn>="+((pageNo-1)*pageSize+1)+" and rn<="+pageNo*pageSize;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(url, username, password);
st = conn.createStatement();
rs = st.executeQuery("select count(*) from emp");
if(rs.next()){
rowCount = rs.getInt(1);
if(rowCount%pageSize == 0){
pageCount = rowCount/pageSize;
}else {
pageCount = rowCount/pageSize + 1;
}
}
rs = st.executeQuery(sql2);
while (rs.next()) {
out.println("<tr>");
out.println("<td>" + rs.getString("ename") + "</td>");
out.println("<td>" + rs.getString("sal") + "</td>");
out.println("</tr>");
}
for(int i=1; i<=pageCount; i++){
out.print("<a href=index.jsp?pageNo=" +i+">" + i + "</a>");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
rs.close();
st.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
%>


</table>
</body>
</html>
<think>好的,我现在需要帮助用户找到关于Oracle数据库分页查询的方法或示例。用户明确提到想了解如何实现分页查询,可能他们正在开发需要分页功能的应用程序,或者在优化现有查询性能。首先,我应该回顾已有的引用内容,看看有哪些可用的信息。 引用1提到了使用ROWNUM和ROW_NUMBER()窗口函数,还有分析函数。方法一是用ROWNUM,这应该是比较传统的方法。引用3详细讨论了两种分页方案,强调高效利用索引和ROWNUM的应用。用户可能需要具体的SQL示例,而不仅仅是理论。 接下来,我需要整理这些信息,给出几种常见的分页方法,并附上示例。首先,ROWNUM方法,这是Oracle经典的分页方式。需要注意子查询的使用,因为直接使用ROWNUM在外部查询会有问题,所以需要在子查询中先排序并应用ROWNUM。例如,第三页,每页10条,应该是ROWNUM <=30,然后外层取RN >20。 然后是ROW_NUMBER()窗口函数,这种方法可能更直观一些,通过给行编号然后筛选区间。接着是OFFSET-FETCH,但Oracle 12c以上才支持,用户可能在使用旧版本,所以需要注明版本要求。此外,引用2提到了MyBatis和PageHelper,用户可能对如何在Java框架中实现分页感兴趣,可以简要提及,但用户的问题主要是关于SQL示例,所以这部分可能作为扩展。 需要确保每个示例都正确,符合Oracle的语法,比如正确使用别名和子查询。同时,要指出不同方法的优缺点,比如ROWNUM在性能上的考虑,是否需要索引优化,以及方案选择的情境。比如,方案一适合有高效索引的情况,方案二则更灵活,但都需要主查询的条件优化。 用户可能还关心哪种方法效率更高,引用3提到两种方案的比较,需要根据具体情况评估,比如索引的使用情况。此外,注意提醒用户排序字段的选择,如果没有正确的ORDER BY,分页结果可能不一致。 最后,生成相关问题,帮助用户深入理解,比如性能优化、与框架集成、不同版本的区别等。这些问题应该覆盖用户可能遇到的后续疑问。</think>关于Oracle数据库分页查询的实现,主要有以下几种典型方法及示例: ### 一、ROWNUM分页法(经典方案) ```sql -- 查询第3页(每页10条) SELECT * FROM ( SELECT t.*, ROWNUM RN FROM ( SELECT * FROM employees WHERE department_id = 50 ORDER BY hire_date DESC -- 必须明确排序条件 ) t WHERE ROWNUM <= 30 -- 页数*每页条数 ) WHERE RN > 20; -- (页数-1)*每页条数 ``` **特点**:通过三层嵌套查询实现[^3] - 最内层:确定排序规则 - 中间层:生成连续ROWNUM - 外层:过滤目标区间 ### 二、ROW_NUMBER()窗口函数 ```sql SELECT * FROM ( SELECT e.*, ROW_NUMBER() OVER (ORDER BY hire_date DESC) RN FROM employees e WHERE department_id = 50 ) WHERE RN BETWEEN 21 AND 30; ``` **优势**:语法更简洁直观,适合需要动态计算排名的场景 ### 三、OFFSET-FETCH(12c+) ```sql SELECT * FROM employees WHERE department_id = 50 ORDER BY hire_date DESC OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY; ``` **注意**:仅适用于Oracle 12c及以上版本 ### 四、MyBatis集成示例 通过`PageHelper`插件简化实现[^2]: ```xml <!-- MyBatis配置 --> <select id="selectPage" resultType="Employee"> SELECT * FROM employees WHERE department_id = #{deptId} ORDER BY hire_date DESC </select> ``` Java调用: ```java PageHelper.startPage(3, 10); // 第3页,每页10条 List<Employee> list = employeeMapper.selectPage(50); ``` ### 性能优化建议 1. **索引优化**:排序字段和查询条件字段应建立复合索引,例如: ```sql CREATE INDEX idx_dept_hire ON employees(department_id, hire_date DESC) ``` 2. **避免全表扫描**:WHERE条件应能有效利用索引 3. **减少返回字段**:只选择必要字段而非`SELECT *`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值