2017-01-10 100 views
1

我有一个程序,我的用户可以用它查找过去7天发生的所有数据流量。我使用存储过程来获取数据 - 每次有250条记录(用户可以通过该页面进行翻页)。问题是,当用户想看到这些数据时,用户会得到很多超时。SQL Server 2008等同于带有WHERE子句的FETCH OFFSET

这是我试图优化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分钟才能获得我想要的数据。为了使存储过程更快的I insered WHERE子句来筛选插入的山坳(也是我做了这列的索引),并使用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 

这个版本给了我大约2s的数据。唯一的问题是,我在Microsoft SQL Server 2014上工作,但我的用户使用SQL Server 2008+。现在的问题是,OFFSET FETCH dosn't在Server 2008中工作。现在我无能为力,我可以优化我的存储过程,它在SQl Server 2008上运行速度快。

我很感谢任何帮助:)

回答

0

试试这个方法来处理分页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] 
+0

谢谢你的回答。说实话:我不知道如何将你的建议插入我的存储过程。 – KatharinaG

+0

您可以在CTE中替换您的选择查询,但'ROW_NUMBER()OVER(ORDER BY [put_column-to-sort-here] DESC)AS [ROW_NO]'列应该在那里对记录进行排序,那么只有我们可以维护记录中的订单序列。 CTE之后的选择脚本将保持不变。 –

+0

好吧,现在我知道了,我改变了我的存储过程,就像你建议的那样,但是现在需要大约3分07分钟才能得到我想要的数据(比如1:35分钟) – KatharinaG