结果存在子集关系的两条SQL语句Count(*)查询优化方法咨询
优化方案
最高效方案:单次扫描同时计算两个计数
你不需要分别执行两次查询,仅通过一次扫描就能同时得到两个结果,全程只会过滤一次C1 = A的数据集,完全避免重复扫描:
SELECT COUNT(*) AS query1_result, COUNT(CASE WHEN C2 = B THEN 1 END) AS query2_result FROM `table` WHERE C1 = A
原理说明:
- WHERE 子句先过滤出所有符合
C1 = A的行,对应Query1的统计范围,直接用COUNT(*)就能得到Query1的结果 - 第二个计数用CASE表达式判断,只有同时满足
C2 = B的行才会返回非NULL值,COUNT会自动忽略NULL值,最终结果就是Query2的统计值
如果你确实需要先缓存Query1结果再计算
如果你的场景需要复用Query1的结果集做其他操作,可以用CTE或者临时表实现:
方案1:公共表表达式(CTE,支持MySQL 8.0+、PostgreSQL、Oracle等主流数据库)
WITH query1_set AS ( SELECT * FROM `table` WHERE C1 = A ) SELECT (SELECT COUNT(*) FROM query1_set) AS query1_result, (SELECT COUNT(*) FROM query1_set WHERE C2 = B) AS query2_result
方案2:临时表(适配低版本不支持CTE的数据库)
-- 写入Query1结果到临时表 CREATE TEMPORARY TABLE temp_query1 AS SELECT C2 FROM `table` WHERE C1 = A; -- 统计两个结果 SELECT COUNT(*) AS query1_result FROM temp_query1; SELECT COUNT(*) AS query2_result FROM temp_query1 WHERE C2 = B;
额外优化建议
如果表还没有针对这两个查询的索引,建议创建联合索引 INDEX idx_c1_c2(C1, C2),可以触发索引覆盖扫描,不需要回表读取整行数据,针对500GB的大表能带来数倍到数十倍的性能提升。
内容的提问来源于stack exchange,提问作者Vikas Gupta
相关产品推荐
相关产品推荐

