计算列,或按触发器更新列以保持统计信息

时间:2017-06-07 09:08:10

标签: .net sql-server calculated-columns

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

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

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

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

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

2 个答案:

答案 0 :(得分:1)

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

因此,这将保留computed column和/或indexed views

  

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

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

  

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

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

  

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

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

答案 1 :(得分:0)

  

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

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

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

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这样的视图。这种类型的一个示例是返回说明管理员报告的活动用户数的视图。