单个 SQL 查询的多个 COUNTS:寻找效率
Several COUNTS on single SQL Query: Looking for efficiency
我只想了解您对查询效率的看法。我正在通过非常大的 table (几百万条记录)计算值。这是 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;
我意识到我正在重复计算同样的事情,我应该能够添加部分结果,但老实说,如果不遍历 table 不止一次,我不知道该怎么做.
实际查询还有大约 20 个 SUM,它们是相同数据的组合。查询需要一段时间到 运行(大约两个小时)。我想知道是否有更好的方法来做到这一点。
非常欢迎任何建议。
谢谢
您可以保留中间标志。我怀疑这会加快您的查询速度,但它会使维护更简单:
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;
如果您的比较实际上比简单的字符串相等更麻烦,这可能会影响性能。
确保您的查询具有完全覆盖索引。这可以带来巨大的不同。确保您的查询计划使用多核。如果您查看查询计划,请查找收集运算符。这与上面的 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
如果所有其他方法都失败了,请考虑将聚合结果缓存在 table 中,该 table 仅包含聚合查询的结果集。原来聚合查询可以运行每两个小时。但是查询缓存table会包含更少的记录,查询起来会容易很多。
我只想了解您对查询效率的看法。我正在通过非常大的 table (几百万条记录)计算值。这是 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;
我意识到我正在重复计算同样的事情,我应该能够添加部分结果,但老实说,如果不遍历 table 不止一次,我不知道该怎么做.
实际查询还有大约 20 个 SUM,它们是相同数据的组合。查询需要一段时间到 运行(大约两个小时)。我想知道是否有更好的方法来做到这一点。
非常欢迎任何建议。
谢谢
您可以保留中间标志。我怀疑这会加快您的查询速度,但它会使维护更简单:
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;
如果您的比较实际上比简单的字符串相等更麻烦,这可能会影响性能。
确保您的查询具有完全覆盖索引。这可以带来巨大的不同。确保您的查询计划使用多核。如果您查看查询计划,请查找收集运算符。这与上面的 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
如果所有其他方法都失败了,请考虑将聚合结果缓存在 table 中,该 table 仅包含聚合查询的结果集。原来聚合查询可以运行每两个小时。但是查询缓存table会包含更少的记录,查询起来会容易很多。