【问题标题】:SQL Server 2008 Paged Row Retrieval and Large TablesSQL Server 2008 分页行检索和大表
【发布时间】:2013-02-24 21:03:06
【问题描述】:

我正在使用 SQL Server 2008 和以下查询从我们的 JSF 应用程序中实现分页数据检索,在下面的代码中,我一次 检索 25 行,按默认排序进行排序按 DESC 顺序排列的列。

SELECT * FROM 
    (  
        SELECT TOP 25 * FROM 
        ( 
            SELECT TOP 25  ...... WHERE CONDITIONS 
            --ORDER BY ... DESC
        )AS INNERQUERY  ORDER BY INNERQUERY.... ASC
    ) 
AS OUTERQUERY 
ORDER BY OUTERQUERY.... DESC 

它有效,但有一个明显的流程。如果用户请求查看最后一页,并且表中有超过 1000 万条记录,则 second TOP Query 必须首先查看 retrieve the 10 million 记录,然后才是first top Query 会挑选出Top 25,看起来像:

SELECT * FROM 
    (  
        SELECT TOP 25 * FROM 
        ( 
            SELECT TOP 10000000  ...... WHERE CONDITIONS 
            --ORDER BY ... DESC
        )AS INNERQUERY  ORDER BY INNERQUERY.... ASC
    ) 
AS OUTERQUERY 
ORDER BY OUTERQUERY.... DESC 

我考虑用 ROW_NUMBER OVER(....) 替换上面的内容,但似乎我遇到了同样的问题,第二个 TOP 语句必须得到整个结果,然后你才能执行where ROW_NUMBER between x and y

您能否指出我在上述方法中的错误以及如何优化它的提示?

【问题讨论】:

  • 这是一个很好的 row_number 示例,您可能会发现它很有用:blogs.x2line.com/al/archive/2005/11/18/1323.aspx
  • 感谢您的链接,我看了看,但正如您自己所见,第一个 SELECT 语句将检索所有行,然后您才能在第二个 SELECT 中使用 between x and y 选择一个范围。我的问题是第一个 Select 语句需要一段时间才能返回,因为记录很多。
  • 查看这个 SO 链接及其对 Greg Hamilton 的文章“A More Efficient Method for Paging Through Large Result Sets”stackoverflow.com/questions/2308220/… 的引用
  • 顺便说一句,很多时候问题是试图为用户提供一些不是绝对必要、有用或合理的东西(是的,我知道用户一直在问这种事情!) .没有人会以 25 行(也不是 500 行)为一组翻阅 1000 万行。他会在第 1000 次迭代之前饿死。那么,如果他真的需要,为什么不提供从头到尾的分页呢?你能让他明白他在问一些疯狂的事情吗?我通常会说服我的客户对他们的查询有这种明显的限制。
  • 大多数客户通常接受的一个选项是能够更改订单,或具有某种过滤器,或两者兼而有之,并将他们的分页限制为 1000 或 2000 个第一条记录。您处于最糟糕的情况:不断变化的数据、大表和非聚集索引……哎哟!这避免了维护辅助表或结构来帮助查询。维护您的非聚集索引以尽可能避免碎片化也很重要。

标签: sql sql-server-2008


【解决方案1】:

我目前正在使用以下代码来检索行子集:

WITH PAGED_QRY (
                   SELECT *, ROW_NUMVER() OVER(ORDER BY Y) AS ROW_NO
                   FROM TABLE WHERE ....
               ) 
SELECT * FROM PAGED_QRY WHERE ROW_NO BETWEEN @CURRENT_INDEX and @ ROWS_TO_RETRIEVE
ORDER BY ROW_NO

其中@current_index@rows_to_retrieve (即150 是您的分页变量。它更干净,更易于阅读。

我也尝试过使用SET ROW_COUNT @ROWS_TO_RETRIEVE,但似乎没有太大区别。

使用上述查询并仔细研究查询的执行路径并修改/创建索引和统计信息,我已经达到了足够令人满意的结果,因此我将其作为答案。在内部查询中仅检索所需行的最初目标似乎还不可能,如果您确实找到了方法,请告诉我。

【讨论】:

    【解决方案2】:

    我们可以进一步改进上述查询。 如果我假设@current_index 是当前页码,那么我们可以将上面的查询重写为:

    WITH PAGED_QRY (
                   SELECT top (@current_index * @rows_to_retrieve) *, ROW_NUMVER() 
                     OVER(ORDER BY Y) AS ROW_NO
                   FROM TABLE WHERE ....
               ) 
     SELECT TOP @ROWS_TO_RETRIEVE FROM PAGED_QRY
     ORDER BY ROW_NO DESC
    

    在这种情况下,我们的内部查询不会返回整个记录集。假设我们的 page_index 为 3,page_size 为 50,那么它将只选择 150 行(即使我们的表包含数百/数千/百万行),我们也可以跳过 where 子句。

    【讨论】:

      猜你喜欢
      • 2015-09-29
      • 1970-01-01
      • 2011-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-20
      • 2014-01-14
      相关资源
      最近更新 更多