33

问题:我需要编写将返回单页行的结果集和总行的存储过程。

解决方案 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:我通过将相同的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 和带有 VS2010 SP1 和 Entity Framework 4.4 的最新 ODP.NET。我需要最终解决方案才能在 EF 4.4 中工作。我确信一般来说可能有更好的分页方法,但我需要它们与 EF 一起工作。

4

7 回答 7

39

如果您已经在使用分析 ( 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

如果您在排序列上有适当的索引,则此方法会更好。在这种情况下,使用两个查询可能更有效(一个查询总行数,一个查询结果)。

这两种方法都是合适的,但一般来说,如果你想要行数和分页集,那么使用分析会更有效,因为你只查询行一次。

于 2012-12-06T09:04:38.633 回答
6

这可能会有所帮助:

   SELECT * FROM 
     ( SELECT deptno, ename, sal, ROW_NUMBER() OVER (ORDER BY ename) Row_Num FROM emp)
     WHERE Row_Num BETWEEN 5 and 10;
于 2012-12-06T14:07:01.597 回答
5

在 Oracle 12C 中,您可以使用限制LIMITOFFSET分页。

示例 - 假设您有一个表,需要使用分页根据数据类型列按降序tab从中获取数据。DATEdt

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://dba-presents.com/index.php/databases/oracle/31-new-pagination-method-in-oracle-12c-offset-fetch

https://oracle-base.com/articles/12c/row-limiting-clause-for-top-n-queries-12cr1#paging

于 2018-07-16T11:06:45.297 回答
1

组织 SQL 代码的一种简洁方式可能是 troughWITH语句。

精简版还实现了结果总数和总页数

例如

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)
于 2019-06-30T05:18:43.787 回答
0

试试这个:

select * from ( select * from "table" order by "column" desc ) where ROWNUM > 0 and ROWNUM <= 5;
于 2014-08-19T17:46:54.053 回答
0

抱歉,这个适用于排序:

SELECT * FROM (SELECT ROWNUM rnum,a.* FROM (SELECT * FROM "tabla" order by "column" asc) a) WHERE rnum BETWEEN "firstrange" AND "lastrange";
于 2014-08-19T17:56:23.327 回答
0

我也遇到了类似的问题。我尝试了上述所有解决方案,但没有一个能给我带来更好的性能。我有一张包含数百万条记录的表格,我需要以 20 页的形式在屏幕上显示它们。我已经完成了以下操作来解决问题。

  1. 在表中添加一个新列 ROW_NUMBER。
  2. 将该列设为主键或在其上添加唯一索引。
  3. 使用填充程序(在我的例子中是 Informatica)用 rownum 填充列。
  4. 使用 between 语句从表中获取记录。(从 LOWER_RANGE 和 UPPER_RANGE 之间的 ROW_NUMBER 表中选择 *)。

如果我们需要在一个巨大的表上进行无条件的分页获取,这个方法是有效的。

于 2015-05-11T07:32:05.553 回答