【问题标题】:Computed column, or update column by trigger to keep statistics计算列,或按触发器更新列以保留统计信息
【发布时间】:2017-06-07 09:08:09
【问题描述】:

对于每个用户,我们的应用程序都会计算一些统计数据,例如他们登录了多少次,或者他们在测验中答错了多少……这可能是各种各样的事情。该应用在 SQL Server 和 .NET Entity Framework 6.1 上运行

目前,统计数据是按需计算的,但随着用户群的增长,这使得应用程序的报告部分变得越来越慢。

我们想知道是使用计算列(持久化或非持久化)还是使用触发器将这些值存储给用户。

你会怎么做呢?在我看来,计算列可能更容易实现,但每次我从表中读取用户时它们都会重新计算,这可能不会比我们现在做的快得多。由于我们会将整个 SQL 查询放入计算列,因此持久化该列似乎也不合适(SQL Server 将如何推断它应该更新计算?)。 触发某些动作似乎更适合我。

为了论证,假设所有计算的统计数据都是其他表中的值的count(*)sum(*),没有比这更有趣的了。

【问题讨论】:

  • 他们登录了多少次:这是一个不断变化的数字,而 他们在测验中答错了多少次似乎是一个“测验”完成后的静态数字。所以你真的有两种截然不同的情况,可能需要不同的方法。
  • 嘿,感谢您的评论,但它们只是两个愚蠢的例子。实际上,它们都是不断变化的数字。

标签: .net sql-server calculated-columns


【解决方案1】:

如果您必须存储计算值,则宁愿让 SQL 引擎为您完成这项工作,而不是通过触发器手动实现。

所以,这将被保留 computed column 和/或 indexed views

每次我从表中读取用户时,它们都会重新计算

仅当您在SELECT包含计算列(并且您没有选择保留它)。这就是为什么查询通常应该只查询需要的列,而不是select *。但是,由于您使用的是 ORM,您可能无法告诉它不要包含昂贵的列 - 这就是为什么您应该更喜欢持久性或使用索引视图的原因 - 以便将其视为您仅加载的单独对象需要时。

SQL Server 将如何推断它应该更新计算?

因为在幕后,SQL Server 自己有效地实现了触发器。但这里的好处是,这些触发器已经过数百万次测试,并且是您不必编写的代码。

为了论证起见,假设所有计算的统计数据都是其他表中的值的count(*)sum(*)

在这种情况下,您不能真正走计算列路由(计算列应该只真正引用自己表中自己的行。有一些古怪的方法可以尝试使用 UDF 绕过它,但我会通常不推荐),所以在这种情况下,我肯定会推荐索引视图。

【讨论】:

    【解决方案2】:

    为了论证的目的,假设所有计算的统计数据都是 count() 和 sum() 的值,没有比这更有趣的了。

    由于您的报告操作非常简单,因此我建议为这些统计信息使用报告表/审计日志表。

    基本前提是所有报告都可以作为简单查询的变体获得

    SELECT COUNT(*) FROM tblUserLog (NO LOCK) WHERE UserID=34
    

    或者在一个稍微复杂的查询中,比如

    SELECT 
      COUNT(*) OVER(PARTITION BY colA ORDER BY colB) as Metric1, 
      SUM(*) OVER (PARTITION BY colD ORDER BY colC) as Metric2
    FROM tblUserLog (NO LOCK) WHERE UserID =34
    

    现在的主要问题是如何填充此表 tblUserLog应该是什么组合

    作曲

    表格的架构应该是通用的,并且必须满足您的所有报告需求,例如要依靠或求和的列。说几句

    LogID (PK, auto increment)
    LogDateTimestamp
    LogType
    UserID
    MetricToSum1
    MetricToSum2
    ....
    

    这是一个非规范化的表格;我不建议对其进行规范化。

    如何填充:

    这绝对不应该通过触发器来完成。查看可能的最佳替代方案,并假设您的 Web 应用程序具有良好的分层架构;您应该有一个日志方法,可以将必要的详细信息异步插入到数据库表中。所以基本上在表上写入与主用户表 CRUD 和按需读取一起异步发生 每当需要报告时。

    对于一个非常简单的操作,我建议您简单地在主实体表上实现一个视图,例如 User。这种类型的一个例子是一个视图,它返回管理员报告的活跃用户数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-15
      • 1970-01-01
      • 2022-01-11
      • 2019-08-14
      • 1970-01-01
      • 2014-04-09
      相关资源
      最近更新 更多