问题:我需要编写存储过程,这些存储过程将返回单行和总行数的结果集。
解决方案A:我创建了两个存储过程,一个返回单个页面的结果集,另一个返回标量 - 总行数。解释计划说第一个sproc的成本为9,第二个的成本为3。
SELECT *
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY D.ID DESC ) AS RowNum, ...
) AS PageResult
WHERE RowNum >= @from
AND RowNum < @to
ORDER BY RowNum
SELECT COUNT(*)
FROM ...
解决方案B:我将所有内容都放在一个sproc中,方法是在结果集中的每个行中添加相同的TotalRows
个数字。这个解决方案感觉很乱,但成本只有9而且只有一个,所以我倾向于使用这个解决方案。
SELECT *
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY D.ID DESC ) RowNum, COUNT(*) OVER () TotalRows,
WHERE RowNum >= from
AND RowNum < to
ORDER BY RowNum;
Oracle中的分页是否有最佳实践?在实践中最常使用哪种上述解决方案?他们中的任何一个被认为是完全错误的?请注意,我的数据库将保持相对较小(小于10GB)。
我正在使用Oracle 11g和最新的ODP.NET与VS2010 SP1和Entity Framework 4.4。我需要最终的解决方案才能在EF 4.4中运行。我相信一般来说可能有更好的分页方法,但是我需要它们与EF合作。
答案 0 :(得分:25)
如果您已经在使用分析(ROW_NUMBER() OVER ...
),那么在同一分区上添加其他分析函数将为查询添加可忽略的成本。
另一方面,还有许多其他方法可以进行分页,其中一种使用rownum
:
SELECT *
FROM (SELECT A.*, rownum rn
FROM (SELECT *
FROM your_table
ORDER BY col) A
WHERE rownum <= :Y)
WHERE rn >= :X
如果您在订购列上有适当的索引,那么此方法将更胜一筹。在这种情况下,使用两个查询可能更有效(一个用于总行数,一个用于结果)。
这两种方法都是合适的,但一般来说,如果你想要行数和分页集,那么使用分析会更有效率,因为你只查询一次行。
答案 1 :(得分:5)
这可能有所帮助:
SELECT * FROM
( SELECT deptno, ename, sal, ROW_NUMBER() OVER (ORDER BY ename) Row_Num FROM emp)
WHERE Row_Num BETWEEN 5 and 10;
答案 2 :(得分:1)
在Oracle 12C中,可以将限制LIMIT
和OFFSET
用于分页。
示例-
假设您有一个表tab
,需要使用分页从DATE
数据类型列dt
的降序中提取数据。
page_size:=5
select * from tab
order by dt desc
OFFSET nvl(page_no-1,1)*page_size ROWS FETCH NEXT page_size ROWS ONLY;
说明:
page_no = 1 page_size = 5
OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY
-仅提取第5行
page_no = 2 page_size = 5
OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY
-提取接下来的5行
以此类推。
参考页-
https://oracle-base.com/articles/12c/row-limiting-clause-for-top-n-queries-12cr1#paging
答案 3 :(得分:0)
试试这个:
select * from ( select * from "table" order by "column" desc ) where ROWNUM > 0 and ROWNUM <= 5;
答案 4 :(得分:0)
抱歉,这个适用于排序:
SELECT * FROM (SELECT ROWNUM rnum,a.* FROM (SELECT * FROM "tabla" order by "column" asc) a) WHERE rnum BETWEEN "firstrange" AND "lastrange";
答案 5 :(得分:0)
我也面临类似的问题。我尝试了以上所有解决方案,没有人给我更好的表现。我有一张包含数百万条记录的表格,我需要在20页的屏幕上显示它们。我已经完成了下面的工作来解决这个问题。
如果我们需要在巨大的表上进行无条件的分页提取,这种方法很有效。
答案 6 :(得分:0)
使用WITH
语句可以简化组织SQL代码的方式。
精简版还实现了结果总数和总页数。
例如
WITH SELECTION AS (
SELECT FIELDA, FIELDB, FIELDC FROM TABLE),
NUMBERED AS (
SELECT
ROW_NUMBER() OVER (ORDER BY FIELDA) RN,
SELECTION.*
FROM SELECTION)
SELECT
(SELECT COUNT(*) FROM NUMBERED) TOTAL_ROWS,
NUMBERED.*
FROM NUMBERED
WHERE
RN BETWEEN ((:page_size*:page_number)-:page_size+1) AND (:page_size*:page_number)
此代码为您提供了一个分页的结果集,其中包含另外两个字段:
TOTAL_ROWS
包含完整SELECTION
的总行数RN
记录的行号它需要2个参数::page_size
和:page_number
来切片您的SELECTION
选择已实现ROW_NUMBER()
字段
WITH SELECTION AS (
SELECT
ROW_NUMBER() OVER (ORDER BY FIELDA) RN,
FIELDA,
FIELDB,
FIELDC
FROM TABLE)
SELECT
:page_number PAGE_NUMBER,
CEIL((SELECT COUNT(*) FROM SELECTION ) / :page_size) TOTAL_PAGES,
:page_size PAGE_SIZE,
(SELECT COUNT(*) FROM SELECTION ) TOTAL_ROWS,
SELECTION.*
FROM SELECTION
WHERE
RN BETWEEN ((:page_size*:page_number)-:page_size+1) AND (:page_size*:page_number)