如何优化含重复条件子查询的SQL调研数据报表?
优化SQL查询:产品评价占比报表
核心优化方案
原方案多次重复扫描Opinions表,导致性能随数据量增长急剧下降。改用一次聚合+关联的方式,既能大幅提升性能,又能简化后续维护:
SELECT p.Name, -- 处理无评价产品的除数为0问题 CASE WHEN op.TotalOpinions = 0 THEN 0.0 ELSE 1.0 * op.EasyToUseCount / op.TotalOpinions END AS EasyToUse, CASE WHEN op.TotalOpinions = 0 THEN 0.0 ELSE 1.0 * op.GoodPriceCount / op.TotalOpinions END AS GoodPrice, CASE WHEN op.TotalOpinions = 0 THEN 0.0 ELSE 1.0 * op.DurableCount / op.TotalOpinions END AS Durable FROM Products p LEFT JOIN ( SELECT ProductId, COUNT(*) AS TotalOpinions, SUM(CAST(IsEasyToUse AS INT)) AS EasyToUseCount, SUM(CAST(IsGoodPrice AS INT)) AS GoodPriceCount, SUM(CAST(IsDurable AS INT)) AS DurableCount FROM Opinions GROUP BY ProductId ) op ON p.Id = op.ProductId
优化说明
- 性能提升:仅扫描一次
Opinions表,通过GROUP BY ProductId完成所有统计计算,避免原方案中每个评价维度执行两次子查询(多次重复扫描数据),100万行数据场景下耗时会大幅降低。 - 简化维护:后续新增评价字段(如
IsRecommend),只需在子查询中添加一行SUM(CAST(IsRecommend AS INT)) AS RecommendCount,再在主查询中补充对应占比计算即可,无需重复编写子查询逻辑。 - 异常处理:通过
CASE语句处理无评价产品的除数为0问题,避免查询报错,同时保证报表完整性(无评价产品占比显示为0)。 - 索引优化建议:给
Opinions表创建包含统计字段的非聚集索引,进一步加速聚合查询:
CREATE NONCLUSTERED INDEX IX_Opinions_ProductId ON Opinions(ProductId) INCLUDE(IsEasyToUse, IsGoodPrice, IsDurable)
该索引让数据库无需扫描整张表,直接从索引中获取所需统计数据。
内容的提问来源于stack exchange,提问作者Patrick Ragnar
相关产品推荐
相关产品推荐

