如何优化按班级分组查询平均数量的SQL查询语句?
优化班级平均数量查询的方案
嘿,这个场景我太熟悉了!你原来用WHERE IN子查询的方式虽然能得到结果,但当两张表的数据量变大时,性能很容易掉链子——尤其是子查询返回的id列表很长的时候,数据库得反复做匹配查找,效率很低。咱们换个思路,用**表关联(JOIN)**来重构查询,不仅逻辑更清晰,执行效率也会高很多。
先还原你原来的查询逻辑(大概是这样)
你之前的写法可能类似下面这样,先按班级分组获取对应的id列表,再嵌套子查询计算平均值:
SELECT t1.班级, (SELECT AVG(t2.数量) FROM TABLE2 t2 WHERE t2.table1_id IN (SELECT id FROM TABLE1 WHERE 班级 = t1.班级)) AS 平均数量 FROM TABLE1 t1 GROUP BY t1.班级;
优化后的查询语句
直接通过JOIN关联两张表,然后按班级分组计算平均值,一步到位:
SELECT t1.班级, AVG(t2.数量) AS 平均数量 FROM TABLE1 t1 JOIN TABLE2 t2 ON t1.id = t2.table1_id GROUP BY t1.班级;
为什么这个方案更优?
- 避免了嵌套子查询的多次执行:数据库可以一次性完成表关联和分组计算,执行计划更高效,不会反复对子查询求值。
- 更容易利用索引加速:关联操作依赖于两张表的关联字段,合理建索引能大幅提升查询速度。
进阶优化:添加合适的索引
如果数据量较大,给这两个字段建索引会让查询速度再上一个台阶:
- 给
TABLE2建覆盖索引(查询时无需回表取数据):
CREATE INDEX idx_table2_table1_id_quantity ON TABLE2(table1_id, 数量);
- 给
TABLE1建联合索引(分组和关联时更快定位数据):
CREATE INDEX idx_table1_class_id ON TABLE1(班级, id);
特殊场景处理:保留无对应记录的班级
如果有些班级在TABLE1里存在,但TABLE2没有对应的数量记录,上面的JOIN会过滤掉这些班级。如果需要保留它们并显示平均数量为0,可以用LEFT JOIN配合COALESCE:
SELECT t1.班级, COALESCE(AVG(t2.数量), 0) AS 平均数量 FROM TABLE1 t1 LEFT JOIN TABLE2 t2 ON t1.id = t2.table1_id GROUP BY t1.班级;
内容的提问来源于stack exchange,提问作者Jens




