【问题标题】:Several COUNTS on single SQL Query: Looking for efficiency单个 SQL 查询上的几个 COUNTS:寻找效率
【发布时间】:2021-01-10 23:51:22
【问题描述】:

我只是希望您对查询的效率提出意见。我正在通过一个非常大的表(数百万条记录)计算值。这是 MSSQL,但我认为它应该适用于任何数据库引擎。我现在正在做的事情如下:

SELECT Task,
    COUNT(*) as Total,
    SUM(CASE WHEN Status = 'Active' THEN 1 ELSE 0 END) AS Active,
    SUM(CASE WHEN Status = 'Active' AND AppType = 'MOBILE' THEN 1 ELSE 0 END) AS ActiveMobile,
    SUM(CASE WHEN Status = 'Active' AND AppType = 'WEB' THEN 1 ELSE 0 END) AS ActiveWeb,
    SUM(CASE WHEN Status = 'OnHold' THEN 1 ELSE 0 END) AS onHold,
    SUM(CASE WHEN Status = 'onHold' AND AppType = 'MOBILE' THEN 1 ELSE 0 END) AS onHoldMobile,
    SUM(CASE WHEN Status = 'onHold' AND AppType = 'WEB' THEN 1 ELSE 0 END) AS onHoldWeb,
    SUM(CASE WHEN Status = 'Active' OR Status = 'onHold' THEN 1 ELSE 0 END) AS ActiveAndOnHold,
    SUM(CASE WHEN (Status = 'Active' OR Status = 'onHold') AND AppType = 'MOBILE' THEN 1 ELSE 0 END) AS ActiveAndOnHoldMobile,
    SUM(CASE WHEN (Status = 'Active' OR Status = 'onHold') AND AppType = 'WEB' THEN 1 ELSE 0 END) AS ActiveAndOnHoldWeb
FROM events
GROUP BY Task;

我意识到我在重新计算同一件事,我应该能够添加部分结果,但老实说,如果不多次遍历表格,我无法弄清楚如何做到这一点。

实际查询还有大约 20 个 SUM 以及相同数据的组合。查询需要一段时间才能运行(大约两个小时)。我想知道是否有更好的方法来做到这一点。

非常欢迎任何建议。

谢谢

【问题讨论】:

  • 除了查询优化之外,您还可以查看您的 SQL Server 实例是否还有一些资源,并使用其最大程度的并行性(又名maxdop)。如果它与 0 不同,则可以在查询后添加 option (maxdop x)x 是查询计划中每个运算符的最大线程数(0 = 无限制)。如果您要在接近生产的任何地方运行它,请密切关注 CPU 和 I/O 负载!
  • 2 小时!!!数据有多大?在这种情况下,我预计成本主要是group by 的数据移动,而不是sum()s 的数量。
  • 谢谢@Sander,我会检查一下。
  • @Gordon Linoff。我希望我知道为什么需要这么长时间。
  • CASE WHEN Status = 'Active' AND Status = 'onHold',如果不是拼写错误,则始终为 false:0 ,,,您可以将查询中已计算的 sum(active)+sum(onhold) (Active, onHold) 添加到获得 active&onhold 的总和.. active(mobile)+onhold(mobile) 等也是如此......

标签: sql sql-server count sum multiple-conditions


【解决方案1】:

您可以保留中间标志。我怀疑这会加快您的查询速度,但它会使维护变得更简单:

SELECT Task, COUNT(*) as Total,
        SUM(is_active) AS Active,
        SUM(is_active * is_mobile) AS ActiveMobile,
        . . .
FROM events e CROSS APPLY
     (VALUES (CASE WHEN Status = 'Active' THEN 1 ELSE 0 END),
             (CASE WHEN Status = 'OnHold' THEN 1 ELSE 0 END),
             (CASE WHEN AppType = 'WEB' THEN 1 ELSE 0 END),
             (CASE WHEN AppType = 'MOBILE' THEN 1 ELSE 0 END),
             . . .
     ) v(is_active, is_onhold, is_web, is_mobile)
GROUP BY Task;

如果您的比较实际上比简单的字符串相等更麻烦,这可能会影响性能。

【讨论】:

  • 谢谢@Gordon Linoff,你说得对,那就更干净了。谢谢你的主意。我会测试一下。
【解决方案2】:

确保您的查询具有完全覆盖的索引。这可以产生巨大的影响。确保您的查询计划使用多个核心。如果您查看查询计划,请查找聚集运算符。这与上面的 maxdop 建议有关。考虑使用获取行数的详细详细信息子查询。然后另一个查询将您的字段分解为最终结果。

select F1, sum(case when A = 1 then ItemCount else 0 end) SummaryField
from 
(
  select F1, A, count(*) ItemCount
  from T1
  group by F1, A
) T2
group by F1 

如果所有其他方法都失败了,请考虑将聚合结果缓存在一个仅包含聚合查询结果集的表中。原始聚合查询可以每两个小时运行一次。但是查询缓存表会包含更少的记录,查询起来会容易很多。

【讨论】:

    猜你喜欢
    • 2021-01-26
    • 1970-01-01
    • 1970-01-01
    • 2017-05-27
    • 2013-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多