【问题标题】:SQL Server 2008 equivalent for FETCH OFFSET with WHERE clauseSQL Server 2008 等效于带有 WHERE 子句的 FETCH OFFSET
【发布时间】:2017-01-10 07:57:16
【问题描述】:

我有一个程序,我的用户可以使用该程序查找过去 7 天发生的所有数据流量。我使用存储过程来获取该数据 - 一次 250 条记录(用户可以翻页)。问题是,当用户想要查看这些数据时,他们会遇到很多超时。

这是我尝试优化ist之前的存储过程。

@MaxRecCount INT,
@PageOffset INT,
@IncludeData BIT

SELECT [Client], [Schema], [Version], [Records], [Fetched], [Receipted], [ProvidedAt], [FetchedAt], [ReceiptedAt],[PacketIds], [Record] FROM (
    SELECT TOP(@MaxRecCount) MAX(bai_ExportPendingArchive.[UserName]) AS Client,
    MAX(bai_ExportPendingArchive.Category) AS [Schema],
    MAX(bai_ExportPendingArchive.ContractVersion) AS [Version],
    COUNT(*) AS [Records],
    SUM (CASE WHEN bai_ExportPendingAckArchive.ExportPendingId IS NULL THEN 0 ELSE 1 END) as [Fetched],
    SUM (CASE WHEN bai_ExportPendingAckArchive.Receipted IS NULL THEN 0 ELSE 1 END) as [Receipted],
    MAX(bai_ExportArchive.Inserted) AS [ProvidedAt],
    MAX(CASE WHEN bai_ExportPendingAckArchive.ExportPendingId IS NULL THEN NULL ELSE bai_ExportPendingAckArchive.Inserted END) AS [FetchedAt],
    MAX(CASE WHEN bai_ExportPendingAckArchive.Receipted IS NULL THEN NULL ELSE bai_ExportPendingAckArchive.Receipted END) AS [ReceiptedAt],
    bai_ExportArchive.PacketIds AS [PacketIds],
    NULL AS [Record],
    ROW_NUMBER() Over (Order By MAX(bai_ExportArchive.Inserted) desc) as [RowNumber]
FROM bai_ExportArchive
INNER JOIN bai_ExportPendingArchive ON bai_ExportArchive.Id = bai_ExportPendingArchive.ExportId
LEFT OUTER JOIN bai_ExportPendingAckArchive ON bai_ExportPendingAckArchive.ExportPendingId = bai_ExportPendingArchive.Id
GROUP BY bai_ExportPendingArchive.[UserName], bai_ExportArchive.PacketIds, bai_ExportPendingArchive.Category
) AS InnerTable WHERE RowNumber > (@PageOffset * @MaxRecCount)  and RowNumber <= (@PageOffset * @MaxRecCount + @MaxRecCount)
ORDER BY RowNumber

@MaxRecCount、@PageOffset 和 @IncludeData 是来自我的 C# 方法的参数。 这个版本需要大约 1:35 分钟才能得到我想要的数据。为了使存储过程更快,我插入了一个 WHERE 子句来过滤插入的 col(我也在此列上创建了一个索引)并使用 OFFSET FETCH:

优化后的存储过程:

@MaxRecCount INT, 
@PageOffset INT, 
@IncludeData BIT 

Declare @pageStart int
Declare @pageEnd int

SET @pageStart = @PageOffset * @MaxRecCount
SET @pageEnd = @pageStart + @MaxRecCount + 50

IF @IncludeData = 0
    BEGIN
        SELECT [Client], [Schema], [Version], [Records], [Fetched], [Receipted], [ProvidedAt], [FetchedAt], [ReceiptedAt],[PacketIds], [Record] FROM (
            SELECT TOP(@MaxRecCount) bai_ExportPendingArchive.[UserName] AS Client,
            bai_ExportPendingArchive.Category AS [Schema],
            MAX(bai_ExportPendingArchive.ContractVersion) AS [Version],
            COUNT(*) AS [Records],
            SUM (CASE WHEN bai_ExportPendingAckArchive.ExportPendingId IS NULL THEN 0 ELSE 1 END) as [Fetched],
            SUM (CASE WHEN bai_ExportPendingAckArchive.Receipted IS NULL THEN 0 ELSE 1 END) as [Receipted],
            MAX(bai_ExportArchive.Inserted) AS [ProvidedAt],
            MAX(CASE WHEN bai_ExportPendingAckArchive.ExportPendingId IS NULL THEN NULL ELSE bai_ExportPendingAckArchive.Inserted END) AS [FetchedAt],
            MAX(CASE WHEN bai_ExportPendingAckArchive.Receipted IS NULL THEN NULL ELSE bai_ExportPendingAckArchive.Receipted END) AS [ReceiptedAt],
            bai_ExportArchive.PacketIds AS [PacketIds],
            NULL AS [Record],
            ROW_NUMBER() Over (Order By MAX(bai_ExportArchive.Inserted) desc) as [RowNumber]
            FROM bai_ExportArchive
            INNER JOIN bai_ExportPendingArchive ON bai_ExportArchive.Id = bai_ExportPendingArchive.ExportId
            LEFT OUTER JOIN bai_ExportPendingAckArchive ON bai_ExportPendingAckArchive.ExportPendingId = bai_ExportPendingArchive.Id
            Where bai_ExportArchive.Inserted <= (Select bai_ExportArchive.Inserted from bai_ExportArchive Order by bai_ExportArchive.Inserted DESC Offset @pageStart ROWS FETCH NEXT 1 ROWS Only)
            And bai_ExportArchive.Inserted > (Select bai_ExportArchive.Inserted from bai_ExportArchive Order by bai_ExportArchive.Inserted DESC Offset @pageEnd ROWS FETCH NEXT 1 ROWS Only)
            GROUP BY bai_ExportPendingArchive.[UserName], bai_ExportArchive.PacketIds, bai_ExportPendingArchive.Category
            ) AS InnerTable 
        ORDER BY RowNumber

这个版本给我大约 2 秒的数据。唯一的问题是,我在 Microsoft SQL Server 2014 上工作,但我的用户使用 SQL Server 2008+。现在的问题是,OFFSET FETCH 在 Server 2008 中不起作用。现在我不知道如何优化我的存储过程,它是快速的并且可以在 SQl Server 2008 上工作。

感谢您的帮助:)

【问题讨论】:

    标签: sql sql-server-2008 stored-procedures sql-server-2012


    【解决方案1】:

    试试这个方法处理SQL Server 2005/2008中的分页。

    首先使用CTE 进行选择查询,并使用ROW_NUMBER() 列来标识记录号/计数。之后,您可以使用您的PAGE_NUMBERPAGE_COUNT 从此CTE 中选择一系列记录。示例如下

    DECLARE @P_PAGE_NUM     INT =    0
            ,@P_PAGE_SIZE   INT =   20
    
        ;WITH CTE
        AS
        (   /*SELECT    ROW_NUMBER() OVER (ORDER BY COL_to_SORT DESC)   AS  [ROW_NO]
                    ,...
            WHERE   ....
            */ -- You can replace your select query here, but column [ROW_NO] should be there in your select list.
               --ie ROW_NUMBER() OVER (ORDER BY put_column-to-sort-here DESC)   AS  [ROW_NO] 
        )
    
        SELECT  *
                --,(    SELECT COUNT(*) FROM CTE) AS    [TOTAL_ROW_COUNT]
        FROM    CTE
        WHERE   (   
                    ISNULL(@P_PAGE_NUM,0)   =   0   OR
                    [ROW_NO]    BETWEEN (   @P_PAGE_NUM - 1) *  @P_PAGE_SIZE + 1  
                                    AND     @P_PAGE_NUM      *  @P_PAGE_SIZE
                )
        ORDER BY    [ROW_NO]
    

    【讨论】:

    • 感谢您的回答。老实说:我不知道如何将您的建议插入到我的存储过程中。
    • 您可以在 CTE 中替换您的选择查询,但是应该有 'ROW_NUMBER() OVER (ORDER BY [put_column-to-sort-here] DESC) AS [ROW_NO]' 列来对记录,那么只有我们可以在记录中维护一个顺序序列。并且 CTE 之后的 Select 脚本将保持不变。
    • 好的,现在我明白了,我按照你的建议更改了我的存储过程,但现在大约需要 3:07 分钟才能获得我想要的数据(更改之前是 1:35 分钟)跨度>
    猜你喜欢
    • 2016-03-11
    • 2013-11-12
    • 2014-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-06
    • 1970-01-01
    相关资源
    最近更新 更多