1

我有具有以下结构的存储过程

WITH ItemsContact (
    IsCostVariantItem
    ,ItemID
    ,AttributeSetID
    ,ItemTypeID
    ,HidePrice
    ,HideInRSSFeed
    ,HideToAnonymous
    ,IsOutOfStock
    ,AddedOn
    ,BaseImage
    ,AlternateText
    ,SKU
    ,[Name]
    ,DownloadableID
    ,[Description]
    ,ShortDescription
    ,[Weight]
    ,Quantity
    ,Price
    ,ListPrice
    ,IsFeatured
    ,IsSpecial
    ,ViewCount
    ,SoldItem
    ,TotalDiscount
    ,RatedValue
    ,RowNumber
    )
AS (
    SELECT ------,
        ROW_NUMBER() OVER (
            ORDER BY i.[ItemID] DESC
            ) AS RowNumber
    FROM -------
    )
    ,rowTotal (RowTotal)
AS (
    SELECT MAX(RowNumber)
    FROM ItemsContact
    )
SELECT CONVERT(INT, r.RowTotal) AS RowTotal
    ,c.*
FROM ItemsContact c
    ,rowTotal r
WHERE RowNumber >= @offset
    AND RowNumber <= (@offset + @limit - 1)
ORDER BY ItemID

当我执行这个时,我从执行计划中找到

SQL Server Execution Times:
   CPU time = 344 ms,  elapsed time = 362 ms.

现在我删除第二个 cte 即 rowTotal

WITH ItemsContact (
    IsCostVariantItem
    ,ItemID
    ,AttributeSetID
    ,ItemTypeID
    ,HidePrice
    ,HideInRSSFeed
    ,HideToAnonymous
    ,IsOutOfStock
    ,AddedOn
    ,BaseImage
    ,AlternateText
    ,SKU
    ,[Name]
    ,DownloadableID
    ,[Description]
    ,ShortDescription
    ,[Weight]
    ,Quantity
    ,Price
    ,ListPrice
    ,IsFeatured
    ,IsSpecial
    ,ViewCount
    ,SoldItem
    ,TotalDiscount
    ,RatedValue
    ,RowNumber
    )
AS (
    SELECT ------,
        ROW_NUMBER() OVER (
            ORDER BY i.[ItemID] DESC
            ) AS RowNumber
    FROM -------
    )
SELECT c.*
FROM ItemsContact c
    ,rowTotal r
WHERE RowNumber >= @offset
    AND RowNumber <= (@offset + @limit - 1)
ORDER BY ItemID

并将执行计划显示为

SQL Server Execution Times:
   CPU time = 63 ms,  elapsed time = 61 ms.

我计算 rowtotal 的第一个代码工作正常,但需要更多时间。我的问题是为什么MAX(RowNumber)要花这么长时间以及如何优化此代码。在此先感谢您的帮助。

4

2 回答 2

1

由于MAX(RowNumber)将始终等于总行数,请尝试仅使用:

SELECT ------,
    ROW_NUMBER() OVER (
        ORDER BY i.[ItemID] DESC
        ) AS RowNumber,
    COUNT(*) OVER () as RowTotal
FROM -------

作为您的第一个 CTE。

于 2013-07-17T07:28:20.240 回答
1

按照您的编码方式,您的 SQL 存在语法错误。另一件事是,如果您rowTotal从第二个查询中删除,它根本就不起作用,因为它仍然具有对它的引用。所以我不知道这些第二次执行时间来自哪里。

但是,如果我使用代码块作为模板并删除错误,则此查询的执行计划应该非常简单:您应该对表和排序运算符进行(聚集)索引扫描,以及其他一些运算符(a 的序列投影排名 ROW_NUMBER 函数,一些连接运算符,如嵌套循环等)。聚集索引扫描和排序应该是大多数处理器密集型操作。-------

SQL server 应该在这里计算每一行的行号,找到它的最大值以及从输入变量计算的两个行号之间的约束结果。显然有一个使用这个查询构建的分页功能,并且在 SO 上的 SQL Server 中有很多关于分页的内容,所以查找它,您可以找到很多相关信息。

如果有基于此查询的已知层,您应该更改它。它使用额外的不必要的列,max(row_number(ID))因为它在所有行(38k?)中都是恒定的,并且在逻辑上只有一个标量值。相反,您应该count(*)按照@Damien_The_Unbeliever 在其解决方案中的建议返回,但将其与结果集分开。通过这种方式,您可以简化查询,取而代之的是这样的:

SELECT
  N,
  *
FROM 
  YourTable 
  CROSS apply(
    SELECT N = ROW_NUMBER() OVER (ORDER BY ItemID DESC)
  ) x
WHERE N BETWEEN @offset AND @offset + @limit - 1
ORDER BY ItemID

在下一个查询中应该很容易获得结果计数。如果你有一个很大的表,你可以用这个方法计算大概的行数。

PS 如果您尚未检查执行计划是否存在索引问题,请执行此操作。

于 2013-07-17T09:38:59.087 回答