大量 sum() 的 SQL 性能

Posted

技术标签:

【中文标题】大量 sum() 的 SQL 性能【英文标题】:SQL performance of a large number of sum()s 【发布时间】:2014-10-31 23:42:03 【问题描述】:

在我的 J2EE Web 应用程序中,我需要生成一个条形图,表示系统中users 与特定alerts 的百分比。 (编辑 - 我忘了提,该图只处理与每个用户的第一个 situation 相关联的警报,因此是 min(date) )。

我的数据库架构的简化(但结构相似)版本如下:

users  id, name 
situations  id, user_id, date 
alerts  id, situation_id,  alertA, alertB 

其中userssituations 是 1-n,situationsalerts 是 1-1。

我省略了数据类型,但警报(alertA 和 B)是布尔值。在我的实际案例中,有很多这样的警报(30-ish)。

到目前为止,这是我想出的:

select sum(alerts.alertA), sum(alerts.alertB)
form alerts, (
    select id, min(date)
    from situations
    group by user_id) as situations
where situations.id = alerts.situation_id;

然后将这些总和除以

select count(users.id) from users;

这似乎远非理想。

您对如何改进查询的建议/建议将不胜感激(或者我可能需要重新考虑我的数据库架构)...

谢谢,

安东尼

PS。我还考虑在更新警报表时使用触发器来刷新特定于图表的表,但我想这是不同查询的主题(如果结果有问题)。

【问题讨论】:

【参考方案1】:

首先,再次考虑您的架构。您将有很多不同的警报,并且您可能不想为每个警报添加一个列。

考虑将alerts 表更改为 id, situation_id, type, value ,其中type 将是(A,B,C,....)value 将是您的布尔值。

然后您计算百分比的任务将分为:

(1)统计用户总数:

SELECT COUNT(id) AS total FROM users

(2) 找到每个用户的“第一个”情况:

SELECT situations.id, situations.user_id
-- selects the minimum date for every user_id
FROM (SELECT user_id, MIN(date) AS min_date
      FROM situations
      GROUP BY user_id) AS first_situation
-- gets the situations.id for user with minimum date
JOIN situations ON
  first_situation.user_id = situations.user_id AND
  first_situation.min_date = situations.date
-- limits number of situations per user to 1 (possible min_date duplicates)
GROUP BY user_id

(3) 统计在子查询中的至少一种情况下设置警报的用户数:

SELECT
  alerts.type,
  COUNT(situations.user_id)
FROM ( ... situations.user_id, situations.id ... ) AS situations
JOIN alerts ON
  situations.id = alerts.situation_id
WHERE
  alerts.value = 1
GROUP BY
  alerts.type

将这三个步骤放在一起,得到如下结果:

SELECT
  alerts.type,
  COUNT(situations.user_id)/users.total
FROM (SELECT situations.id, situations.user_id
      FROM (SELECT user_id, MIN(date) AS min_date
            FROM situations
            GROUP BY user_id) AS first_situation
      JOIN situations ON
        first_situation.user_id = situations.user_id AND
        first_situation.min_date = situations.date
      GROUP BY user_id
     ) AS situations
JOIN alerts ON
  situations.id = alerts.situation_id
JOIN (SELECT COUNT(id) AS total FROM users) AS users
WHERE
  alerts.value = 1
GROUP BY
  alerts.type

所有查询都是从我的脑海中写出来的,没有经过测试。即使它们的工作方式不完全一样,您仍然应该明白这一点!

【讨论】:

抱歉,我忘了提到我只对与第一个 situation 相关联的 alerts 感兴趣——因此是 min(date)。我已经相应地修改了我原来的问题。 我实际上已经考虑将警报重组为每行一个警报模型。在 Web 应用程序方面,这意味着我的 Alertsclass 将只包含一个警报项目列表,我需要进行一些重新布线。我的 isAlertA() 方法只会返回 contains() 或类似的东西 - 不是特别成问题。在我的实际应用程序中,Situations 还包含许多计算指标。你认为这些会从类似的治疗中受益吗?非常感谢 我更新了关于“第一种情况”问题的答案。我希望这会有所帮助! 关于situations 的计算指标。这取决于。如果这些是有限数量的不同计算,我会将它们作为列直接放入situations。相反,如果这些指标都以相同的方式计算,但即仅针对不同的数据子集,或者未来指标的数量会更大(或已经很大),那么我将采用额外表格方法,就像与警报。 创建存储过程或视图将降低 J2EE Web 应用程序中数据库之外的复杂性。您只需要调用该过程或从视图中进行选择,这将是一个单行。您也可以稍后修改您的查询,而无需接触您的 J2EE 源代码,因为它完全存储在 mysql 服务器上。阅读有关何时使用视图的更多信息:***.com/questions/1483580/…dba.stackexchange.com/questions/16372/…

以上是关于大量 sum() 的 SQL 性能的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server性能相关查询

大量非常简单的 sql 查询会影响性能吗?

SQL Server性能优化删除大量数据的方法比较

Oracle种常用性能监控SQL语句

在 SQL 中存储大量传感器数据,优化查询性能

如何解决大量数据的 IN 子句 SQL 查询中的性能问题?