【问题标题】:Performing Aggregate Functions on Multi-Million Row Tables在数百万行表上执行聚合函数
【发布时间】:2010-05-12 16:26:55
【问题描述】:

我在处理数百万行表时遇到了一些严重的性能问题,我觉得我应该能够相当快地获得结果。以下是我所拥有的、我如何查询它以及需要多长时间:

  • 我运行的是 SQL Server 2008 Standard,因此分区目前不是一个选项

  • 我正在尝试汇总过去 30 天内特定帐户的所有广告资源的所有视图。

  • 所有视图都存储在下表中:

创建表 [dbo].[LogInvSearches_Daily]( [ID] [bigint] IDENTITY(1,1) 非空, [Inv_ID] [int] 非空, [Site_ID] [int] 非空, [LogCount] [int] 非空, [LogDay] [smalldatetime] 非空, 约束 [PK_LogInvSearches_Daily] 主键集群 ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY] ) 开 [主要]
  • 此表有 132,000,000 条记录,超过 4 个演出。

  • 表格中的 10 行样本:

ID Inv_ID Site_ID LogCount LogDay -------- ----------- ----------- -------- --- ------------ 1 486752 48 14 2009-07-21 00:00:00 2 119314 51 16 2009-07-21 00:00:00 3 313678 48 25 2009-07-21 00:00:00 4 298863 0 1 2009-07-21 00:00:00 5 119996 0 2 2009-07-21 00:00:00 6 463777 534 7 2009-07-21 00:00:00 7 339976 503 2 2009-07-21 00:00:00 8 333501 570 4 2009-07-21 00:00:00 9 453955 0 12 2009-07-21 00:00:00 10 443291 0 4 2009-07-21 00:00:00 (10 行受影响)
  • 我在 LogInvSearches_Daily 上有以下索引:
/****** 对象:索引 [IX_LogInvSearches_Daily_LogDay] 脚本日期:05/12/2010 11:08:22 ******/ 在 [dbo] 上创建非聚类索引 [IX_LogInvSearches_Daily_LogDay]。[LogInvSearches_Daily] ( [日志日] ASC ) 包括([Inv_ID], [LogCount]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  • 我只需要从特定帐户 ID 的库存中提取库存。我也有关于库存的索引。

我正在使用以下查询来聚合数据并为我提供前 5 条记录。此查询目前需要 24 秒才能返回 5 行:

文本 -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- ------ 选择前 5 名 Sum(LogCount) AS 浏览量 , DENSE_RANK() OVER(ORDER BY Sum(LogCount) DESC, Inv_ID DESC) AS Rank , Inv_ID FROM LogInvSearches_Daily D (NOLOCK) 在哪里 LogDay > DateAdd(d, -30, getdate()) 并且存在( 从 propertyControlCenter.dbo.Inventory (NOLOCK) 中选择 NULL,其中 Acct_ID = 18731 AND Inv_ID = D.Inv_ID ) 按 Inv_ID 分组 (1 行受影响) 文本 -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- ------ |--顶部(顶部表达式:((5))) |--序列项目(DEFINE:([Expr1007]=dense_rank)) |--细分市场 |--细分市场 |--排序(排序方式:([Expr1006] DESC,[D].[Inv_ID] DESC)) |--Stream Aggregate(GROUP BY:([D].[Inv_ID]) DEFINE:([Expr1006]=SUM([LOALogs].[dbo].[LogInvSearches_Daily].[LogCount] as [D].[LogCount] ))) |--排序(ORDER BY:([D].[Inv_ID] ASC)) |--嵌套循环(内连接,外引用:([D].[Inv_ID])) |--嵌套循环(内连接,外引用:([Expr1011],[Expr1012],[Expr1010])) | |--计算标量(DEFINE:(([Expr1011],[Expr1012],[Expr1010])=GetRangeWithMismatchedTypes(dateadd(day,(-30),getdate()),NULL,(6)))) | | |--恒定扫描 | |--Index Seek(OBJECT:([LOALogs].[dbo].[LogInvSearches_Daily].[IX_LogInvSearches_Daily_LogDay] AS [D]), SEEK:([D].[LogDay] > [Expr1011] AND [D].[ LogDay]

我尝试使用 CTE 先获取行并聚合它们,但这并没有更快地运行,并且给了我基本相同的执行计划。

(1 行受影响) 文本 -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- ------ --SET SHOWPLAN_TEXT ON; 使用 getSearches 作为 ( 选择 日志计数 -- , DENSE_RANK() OVER(ORDER BY Sum(LogCount) DESC, Inv_ID DESC) AS Rank , D.Inv_ID FROM LogInvSearches_Daily D (NOLOCK) INNER JOIN propertyControlCenter.dbo.Inventory I (NOLOCK) ON Acct_ID = 18731 AND I.Inv_ID = D.Inv_ID 在哪里 LogDay > DateAdd(d, -30, getdate()) -- 按 Inv_ID 分组 ) SELECT Sum(LogCount) AS 视图,Inv_ID 来自 getSearches 按 Inv_ID 分组 (1 行受影响) 文本 -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------- |--Stream Aggregate(GROUP BY:([D].[Inv_ID]) DEFINE:([Expr1004]=SUM([LOALogs].[dbo].[LogInvSearches_Daily].[LogCount] as [D].[LogCount] ))) |--排序(ORDER BY:([D].[Inv_ID] ASC)) |--嵌套循环(内连接,外引用:([D].[Inv_ID])) |--嵌套循环(内连接,外引用:([Expr1008],[Expr1009],[Expr1007])) | |--计算标量(DEFINE:(([Expr1008],[Expr1009],[Expr1007])=GetRangeWithMismatchedTypes(dateadd(day,(-30),getdate()),NULL,(6)))) | | |--恒定扫描 | |--Index Seek(OBJECT:([LOALogs].[dbo].[LogInvSearches_Daily].[IX_LogInvSearches_Daily_LogDay] AS [D]), SEEK:([D].[LogDay] > [Expr1008] AND [D].[ LogDay]

鉴于我的执行计划中的 Index Seeks 很好,我可以做些什么来让它运行得更快?

更新:

这是没有 DENSE_RANK() 的相同查询运行,它需要完全相同的 24 秒运行,并给我相同的基本查询计划:

文本 -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- ------ --SET SHOWPLAN_TEXT ON 选择前 5 名 Sum(LogCount) AS 浏览量 , Inv_ID FROM LogInvSearches_Daily D (NOLOCK) 在哪里 LogDay > DateAdd(d, -30, getdate()) 并且存在( 从 propertyControlCenter.dbo.Inventory (NOLOCK) 中选择 NULL,其中 Acct_ID = 18731 AND Inv_ID = D.Inv_ID ) 按 Inv_ID 分组 按视图排序,Inv_ID (1 行受影响) 文本 -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- ------ |--排序(前 5 名,排序方式:([Expr1006] ASC,[D].[Inv_ID] ASC)) |--Stream Aggregate(GROUP BY:([D].[Inv_ID]) DEFINE:([Expr1006]=SUM([LOALogs].[dbo].[LogInvSearches_Daily].[LogCount] as [D].[LogCount] ))) |--排序(ORDER BY:([D].[Inv_ID] ASC)) |--嵌套循环(内连接,外引用:([D].[Inv_ID])) |--嵌套循环(内连接,外引用:([Expr1010],[Expr1011],[Expr1009])) | |--计算标量(DEFINE:(([Expr1010],[Expr1011],[Expr1009])=GetRangeWithMismatchedTypes(dateadd(day,(-30),getdate()),NULL,(6)))) | | |--恒定扫描 | |--Index Seek(OBJECT:([LOALogs].[dbo].[LogInvSearches_Daily].[IX_LogInvSearches_Daily_LogDay] AS [D]), SEEK:([D].[LogDay] > [Expr1010] AND [D].[ LogDay]

谢谢,

【问题讨论】:

  • 您能否提供一个您希望看到的输出示例?目前尚不清楚为什么您需要 DENSE_RANK 。
  • 我只需要前 5 名。刚刚发布了一个更新,显示有或没有 DENSE_RANK() 的性能完全相同。

标签: sql tsql sql-server-2008 aggregate large-data-volumes


【解决方案1】:

我还没有通读你的整个问题(我很快就会谈到),但要回答一个早期的评论:你可以在 SQL 中使用分区 views服务器 2008 标准版。它是仅限于企业版的分区(公认更灵活)。

分区视图信息:http://msdn.microsoft.com/en-us/library/ms190019.aspx

关于更广泛的问题,我想知道您是否真的需要那里的 DENSE_RANK。我想知道您是否对 DENSE_RANK 中的 ORDER BY 和查询本身的 ORDER BY 感到困惑。就目前而言,您的 TOP 5 将返回 5 个 undefined 记录,因为 SQL Server 不保证记录的任何顺序,除非指定了 ORDER BY 子句(您还没有这样做)。如果您将 ORDER BY 从 DENSE_RANK 向下移动为整个查询 ORDER BY,如下所示,记录将按照我认为您想要的方式出现,它将消除对昂贵的 DENSE_RANK 聚合函数的需要。

SELECT TOP 5
    SUM([LogCount]) AS [Views],
    [Inv_ID]
FROM [LogInvSearches_Daily] D (NOLOCK)
WHERE 
    [LogDay] > DateAdd(d, -30, getdate())
    AND EXISTS(
        SELECT *
        FROM Inventory (NOLOCK)
        WHERE Acct_ID = 18731
            AND Inv_ID = D.Inv_ID
    )
GROUP BY
    Inv_ID
ORDER BY
    [Views] DESC,
    [Inv_ID]

更新:

这里的时间可能已经用完了:

|--Sort(ORDER BY:([D].[Inv_ID] ASC))

您可以尝试创建一个像这样的覆盖索引:

CREATE NONCLUSTERED INDEX [IX_LogInvSearches_Daily_Perf] ON [dbo].[LogInvSearches_Daily] 
(
    [Inv_ID] ASC,
    [LogDay] ASC
)
INCLUDE
(
    [LogCount]
)

请注意,我还稍微更改了 ORDER BY(Inv_ID 现在按 ASC 而非 DESC 排序)。我怀疑此更改不会以有问题的方式影响结果,但可能有助于提高性能,因为它将以与分组相同的顺序返回行(尽管这可能无关紧要!)。

【讨论】:

  • DENSE_RANK() 与否,结果仍然一样慢。我已经尝试了两种方式,但我仍然无法让它加载速度超过 24 秒。更新以显示没有 DENSE_RANK() 的同一查询的查询计划和时间
  • 我认为索引可以解决问题。现在我只需要弄清楚如何在不关闭整个服务器的情况下创建索引...
【解决方案2】:

除了分区,

根据我们处理比您的更大的表的经验,我们将数据提取到临时表(不是表变量)中并在此基础上进行汇总。不是针对所有查询,而是针对更复杂的查询。

除此之外,我同意 Daniel Renshaw 关于 DENSE_RANK 的观察

我还考虑将 [Inv_ID]、[LogCount] 移动到索引中(不包括,可能使用 DESC 排序)

【讨论】:

  • 嗯,这是汇总表...我们有一个 ms by ms 表,然后这会将所有这些请求累积到几天内。我现在正在尝试查询。我无法将其分解为更多,因为这些将是用户根据需要为其帐户运行的动态查询。
【解决方案3】:

Acct_ID 位于 Inventory 表中,并且似乎有一个自身的索引 (IX_Inventory_Acct_ID)。也许如果 Inventory 在 (Acct_Id, Inv_Id) 上有一个索引,并且 LogInvSearches_Daily 在 (Inv_Id, LogDay) 周围聚集(或至少索引),那么您会有更多的运气。

顺便说一句,我不知道 LogInvSearches_Daily.ID 上的当前聚类索引应该买给你什么。为什么要在磁盘上关闭具有关闭 ID 的记录?

【讨论】:

    猜你喜欢
    • 2019-01-31
    • 2015-09-27
    • 1970-01-01
    • 1970-01-01
    • 2015-06-28
    • 2014-12-12
    • 1970-01-01
    • 2011-01-04
    • 2013-01-14
    相关资源
    最近更新 更多