哪个T-SQL跳过查询更好?

时间:2013-07-19 18:39:13

标签: sql-server performance tsql sql-server-2008-r2 pagination

2015年12月17日 - 更新

自从我问这个问题并且没有真正得到答案以来已经有一段时间了,所以我想我会发布我的团队最终使用的解决方案。

我们最初使用动态SQL选项来启动智能排序。虽然功能这个感觉真的很脏。我们最终提出了以下实现:

--Params
DECLARE 
    @pageSize INT
    , @pageIndex INT
    , @sortBy varchar(30)
    , @sortDirection varchar(4);

SET @pageIndex = 1;
SET @pageSize = 10;
SET @sortBy = 'PolicyCode';
SET @sortDirection = 'ASC';

--Vars
DECLARE @start INT,
        @end INT;

--Page 1-n
SET @pageIndex = 1;
SET @pageSize = 10;

SET @start = (@pageSize * @pageIndex) - (@pageSize - 1);
SET @end = (@pageSize * @pageIndex);

;WITH PolicyCTE AS (
    SELECT p.PolicyId, p.PolicyTypeId, p.PolicyCode, p.PolicyDesc, p.EffectiveDate, p.ExpirationDate
    FROM Policy p INNER JOIN PolicyOrg po ON p.PolicyId = po.PolicyId
)
, PagedResultsCTE AS (
    SELECT
        [PolicyId]
        , [PolicyTypeId]
        , [PolicyCode]
        , [PolicyDesc]
        , [EffectiveDate]
        , [ExpirationDate]
        , CASE
            WHEN @sortBy = 'PolicyTypeId' AND @sortDirection = 'ASC' THEN ROW_NUMBER() OVER (ORDER BY [PolicyTypeId] ASC)
            WHEN @sortBy = 'PolicyTypeId' AND @sortDirection = 'DESC' THEN ROW_NUMBER() OVER (ORDER BY [PolicyTypeId] DESC)
            WHEN @sortBy = 'PolicyCode' AND @sortDirection = 'ASC' THEN ROW_NUMBER() OVER (ORDER BY [PolicyCode])
            WHEN @sortBy = 'PolicyCode' AND @sortDirection = 'DESC' THEN ROW_NUMBER() OVER (ORDER BY [PolicyCode] DESC)
            WHEN @sortBy = 'PolicyDesc' AND @sortDirection = 'ASC' THEN ROW_NUMBER() OVER (ORDER BY [PolicyDesc])
            WHEN @sortBy = 'PolicyDesc' AND @sortDirection = 'DESC' THEN ROW_NUMBER() OVER (ORDER BY [PolicyDesc] DESC)
            WHEN @sortBy = 'EffectiveDate' AND @sortDirection = 'ASC' THEN ROW_NUMBER() OVER (ORDER BY [EffectiveDate])
            WHEN @sortBy = 'EffectiveDate' AND @sortDirection = 'DESC' THEN ROW_NUMBER() OVER (ORDER BY [EffectiveDate] DESC)
            WHEN @sortBy = 'ExpirationDate' AND @sortDirection = 'ASC' THEN ROW_NUMBER() OVER (ORDER BY [ExpirationDate])
            WHEN @sortBy = 'ExpirationDate' AND @sortDirection = 'DESC' THEN ROW_NUMBER() OVER (ORDER BY [ExpirationDate] DESC)
        END AS RowNumber            
    FROM PolicyCTE
)
SELECT PolicyId, PolicyTypeId, PolicyCode, PolicyDesc, EffectiveDate, ExpirationDate
FROM PagedResultsCTE
WHERE RowNumber BETWEEN @start AND @end
ORDER BY RowNumber

GO

通过组合CASE语句和另一个CTE,我们能够按传入的排序标准进行排序,并获得正确的ROWNUMBER()值。然后,在我们的最终选择语句中,我们可以简单地按rownumber列进行排序。

我会避免标记现在回答的问题,以防有人想要解决这个问题。绝对欢迎反馈。

原始帖子

也许拥有更多DBA知识的人可以为我揭示这一点。基本前提:使用存储过程中的优化查询获取分页数据以提高页面加载性能(获取记录1-10,11-20等)。这些表有数千条记录。

我正在使用SQL Server 2008 R2,并提出了以下T-SQL以用于存储过程:

--Params
DECLARE @pageSize INT,
        @pageIndex INT;

SET @pageIndex = 1;
SET @pageSize = 10;

--Vars
DECLARE @start INT,
        @end INT

--Page 1-n
SET @pageIndex = 1;
SET @pageSize = 10;

SET @start = (@pageSize * @pageIndex) - (@pageSize - 1);
SET @end = (@pageSize * @pageIndex)

;WITH PolicyCTE AS
(
    SELECT ROW_NUMBER() OVER (ORDER BY p.PolicyCode) AS RowNumber, 
        p.PolicyId, p.PolicyTypeId, p.PolicyCode, p.PolicyDesc, p.EffectiveDate, p.ExpirationDate
    FROM Policy p INNER JOIN PolicyOrg po ON p.PolicyId = po.PolicyId
)
SELECT PolicyId, PolicyTypeId, PolicyCode, PolicyDesc, EffectiveDate, ExpirationDate
FROM PolicyCTE
WHERE RowNumber BETWEEN @start AND @end
ORDER BY PolicyCode

GO

在我寻找有关如何执行此操作的最佳做​​法的搜索中,我遇到了这篇 MSDN模式和实践文章:How To: Page Records in .NET Applications(适用于SQL 2000并声明该文章已发布日期)。引用特定于用户的记录部分,有点等效的T-SQL将如下所示:

DECLARE
    @pageIndex int,
    @pageSize int,
    @sortBy nvarchar(30)

SET @pageIndex = 0;
SET @pageSize = 10;
SET @sortBy = 'PolicyCode';

DECLARE @rowsToRetrieve int,
        @sortDirFlipped nvarchar(4);

IF @pageIndex < 1 SET @pageIndex = 1;
IF @pageSize < 1 SET @pageSize = 10;

SET @rowsToRetrieve = @pageIndex * @pageSize

DECLARE @sqlString nvarchar(1000);
SET @sqlString = N'
    SELECT PolicyId, PolicyTypeId, PolicyCode, PolicyDesc, EffectiveDate, ExpirationDate
    FROM (
        SELECT TOP ' + CAST(@pageSize AS VARCHAR(10)) +  ' PolicyId, PolicyTypeId, PolicyCode, PolicyDesc, EffectiveDate, ExpirationDate
        FROM (
            SELECT TOP ' + CAST(@rowsToRetrieve AS VARCHAR(10)) +  ' PolicyId, PolicyTypeId, PolicyCode, PolicyDesc, EffectiveDate, ExpirationDate
            FROM (
                SELECT TOP ' + CAST(@rowsToRetrieve AS VARCHAR(10)) +  ' p.PolicyId, p.PolicyTypeId, p.PolicyCode, p.PolicyDesc, p.EffectiveDate, p.ExpirationDate
                FROM Policy p INNER JOIN PolicyOrg po ON p.PolicyId = po.PolicyId
                ORDER BY p.' + @sortBy + '
            ) AS T2
            ORDER BY ' + @sortBy + ' DESC
        ) AS T3
    ) AS T4
    ORDER BY ' + @sortBy + ' ASC';

EXEC(@sqlString)
GO

我已经使用执行计划和客户端统计执行这两项操作,在我看来(绝对不是分析这些结果的专家),MSDN版本的性能更好。我可以收集的部分原因是MSDN版本以较小的记录集开始。但是,我真的不喜欢MSDN版本使用动态查询的事实。我的理解是他们更容易受到SQL注入攻击。

我发现的大多数例子都喜欢第一个样本的形式。有人可以帮我解释这个和网站的原因为什么,除了已经列出的那些,第一种形式会比第二种更好?

0 个答案:

没有答案