MySQL查询优化:仅对必要行分组以优化JOIN操作
简洁的查询优化方案
你的核心问题是原查询里的子查询未提前过滤CaseID,导致先对1000万条记录全表分组,最后只用到10个CaseID,完全浪费了计算资源。临时表虽然有效,但确实不够灵活,这里有两种更简洁的优化思路:
1. 先过滤CaseID再关联分组
把cases表的过滤条件提前嵌入子查询,让laboratory只处理符合Diagnosis=16的CaseID,而不是全表扫描分组:
SELECT c.CaseID, t.val FROM cases c LEFT JOIN ( SELECT MAX(l.LaboratoryValue) AS val, l.CaseID FROM laboratory l -- 先关联过滤后的cases,缩小处理范围 JOIN cases c_filter ON l.CaseID = c_filter.CaseID WHERE l.LaboratoryID = 682 AND c_filter.Diagnosis = 16 GROUP BY l.CaseID ) t ON t.CaseID = c.CaseID WHERE c.Diagnosis = 16;
这个查询里,子查询会先通过c_filter拿到所有Diagnosis=16的CaseID,再和laboratory关联,只对这些匹配的记录分组,数据量瞬间从1000万降到几十条(你的场景里是10个CaseID对应的记录),执行效率和临时表方案一致,但不需要手动创建临时表。
2. 使用相关子查询(最简洁)
如果只需要单个聚合字段(比如最大值),用相关子查询是最紧凑的写法,它会自动感知外层cases的CaseID,直接在laboratory中定位对应记录取最大值:
SELECT c.CaseID, (SELECT MAX(l.LaboratoryValue) FROM laboratory l WHERE l.CaseID = c.CaseID AND l.LaboratoryID = 682) AS val FROM cases c WHERE c.Diagnosis = 16;
这种写法不需要分组,只要laboratory表有(CaseID, LaboratoryID, LaboratoryValue)的复合索引,数据库会直接通过索引定位到每个CaseID对应的记录,快速返回最大值,执行速度同样能达到毫秒级。如果需要多个聚合字段(比如同时取最大、最小值),只要在子查询里添加对应的聚合函数即可,非常灵活。
关键前提:确保索引生效
不管用哪种方案,一定要给laboratory表创建复合索引:
CREATE INDEX idx_laboratory_case_lab_val ON laboratory(CaseID, LaboratoryID, LaboratoryValue);
这个索引能让数据库直接定位到符合条件的记录,避免任何不必要的扫描或排序。
内容的提问来源于stack exchange,提问作者SalkinD
相关产品推荐
相关产品推荐

