【问题标题】:"Indexing" (aka maintaining a table of) aggregate data in SQL Server 2005SQL Server 2005 中的“索引”(也称为维护表)聚合数据
【发布时间】:2010-11-30 02:03:58
【问题描述】:

我有一个维护系统性能数据的表,每条记录都是对某个重要方法的调用,由方法名称、其持续时间和一个令牌组成——对系统的每个请求都被赋予一个唯一的令牌等所有具有相同token的记录都是同一个请求,例如:

CallName    Duration    Token
----------- ----------- -----------
GetData     121         12345
Process     800         12345
SaveData    87          12345

GetData     97          ABCDE
Process     652         ABCDE
SaveData    101         ABCDE

我对按 Token 和 CallName 分组的聚合数据感兴趣,例如:

-- The total duration of each request, in descending order
SELECT Token, SUM(Duration) FROM Requests GROUP BY Token ORDER BY SUM(Duration) DESC

-- The average duration of each call, in descending order
SELECT CallName, AVG(Duration) FROM Requests GROUP BY CallName ORDER BY AVG(Duration) DESC

现在这个表可能非常大,我只会对每个查询的前几条记录感兴趣,因此我已经为这两个查询实现了分页。问题在于,因为这些查询涉及聚合函数,SQL 服务器最终还是会进行表扫描。

肯定其他人以前也遇到过这个问题吗?

我在这里真正需要的是按 Token 分组的 SUM(Duration) 上的“索引”,即我可以在其中执行以下操作的表:

SELECT Token, SumToken FROM RequestTokens ORDER BY SumToken DESC
  • 这真的是个坏主意吗?
  • 如果是这样,有没有更好的方法?
  • 最好的方法是什么? INSERT / UPDATE / DELETE 上的触发器会起作用(我根据旧值和更改的数据更新聚合值),还是在更新此表时手动更新我的“索引”会更好?

到目前为止,触发器是我想出的最佳解决方案,但我已经看到这是一场僵局/一致性的噩梦! :-S

【问题讨论】:

标签: sql-server-2005 group-by aggregate-functions


【解决方案1】:

首先,Token 列上的索引不够吗?这样,给定 Token 值,SQL 查询优化器将只扫描包含您感兴趣的行的索引部分。将其设为聚集索引,您将获得最佳性能。

接下来,您如何知道您有兴趣聚合哪个 Token 值?没有列出日期时间(或时间戳)列,并且 Token 值似乎是随机分配的(与某种形式的升序值相反),所以我猜您在发出查询之前知道要聚合的 Token 值--在哪个索引应该做你想做的事。如果值未知但以某种方式上升,则可以使用多种策略来首先确定最近的 X Token 值,一旦你得到那个/那些 Token,你就会回到部分表扫描。

【讨论】:

  • 如果我只想要 1 个令牌,令牌值就足够了,但是我想根据所有令牌的聚合值进行查询 - 即我想要按聚合值排序的前几个令牌。这通常需要进行表扫描,因为 SQL 服务器必须先计算所有标记的聚合值,然后才能对它们进行排序。
【解决方案2】:

如果可能是基于聚合的视图,甚至可能是索引视图。我对索引视图做的不多,但本文讨论了将它们与复杂的聚合(如 AVG())一起使用。也许它会让你朝着正确的方向前进。

http://msdn.microsoft.com/en-us/library/aa933148%28SQL.80%29.aspx

【讨论】:

  • 非常感谢,我没有意识到索引视图有替代聚合函数。
  • 我最终通过结合索引视图和聚合数据表进行排序,这些数据由触发器和计划作业维护。
【解决方案3】:

我会再试一次,现在我更了解它了。这是导致数据仓库解决方案的常见报告问题,如下所示:您可以添加包含预聚合数据的第二个表吗?这确实是非规范化/冗余数据......但它看起来清晰且定义明确,并且可以满足业务需求。这个想法有几个问题:

如果数据只输入一次,您是否可以修改数据输入例程以同时添加聚合行。如果它随着时间流逝,您将需要重复的过程来“清理”。我根据一般原则避免触发;它们在这里可能会有所帮助,但它们也可能会根据使用模式和数据相互关系占用您的系统。

数据必须是最新的吗?聚合数据是否与详细数据不同步?如果是,多长时间?您可以设置一个每天/每小时/5 分钟运行的 SQL 代理作业,以扫描最近的条目并更新聚合表。 (添加索引的“最后输入”列,这些更新可能会很快。)权衡是您的数据将关闭的时间段。 (但该日期时间列可能指示“何时”数据是准确的。也许您不会在该时间点之后提供聚合数据?)

如果数据在输入后没有变化(没有更新、没有删除、没有迟到的行),这可能会起作用 - 但如果您必须随着时间的推移保持更新,并且聚合数据会发生变化 必须在输入数据的同时可用,维护起来可能是一场噩梦。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    • 2019-07-09
    • 1970-01-01
    • 1970-01-01
    • 2011-05-01
    • 2011-03-13
    • 2010-09-15
    相关资源
    最近更新 更多