MySQL左连接带条件查询耗时28秒,去条件仅1秒的问题排查与优化
MySQL LEFT JOIN 查询性能问题分析与优化方案
嘿,这个问题我在日常调试MySQL查询时碰到过好多次,咱们来拆解下问题根源和优化方案~
问题根源
你把左表(regist_queue)的筛选条件和右表的额外筛选条件都塞进了LEFT JOIN的ON子句里,这是导致查询变慢的核心原因:
- 对于LEFT JOIN来说,
ON子句的作用是定义关联规则,而非筛选主表数据。如果把左表的LocationId、QueueDate这类筛选条件放在ON里,MySQL会先尝试把左表全量数据和右表做关联,之后再过滤符合条件的记录,这会产生大量不必要的关联计算,耗时自然飙升。 - 另外,你用
date(rq.QueueDate)、date(ap.dAppDate)这种函数包裹字段的写法,会导致字段上的索引失效,数据库只能做全表扫描,进一步拖慢查询速度。
优化修改方案
1. 拆分筛选条件的位置
把左表的筛选条件移到WHERE子句中,让MySQL先过滤出左表的有效数据,再进行关联操作,大幅减少后续关联的数据量;右表的额外筛选条件可以保留在ON里(确保LEFT JOIN的特性:左表符合条件的记录全部保留,右表只匹配符合条件的记录)。
2. 避免函数包裹字段,改用范围查询
把date(字段) = 日期的写法改成范围区间查询,这样可以利用字段上的索引,避免全表扫描:
- 原写法:
date(rq.QueueDate) = CURRENT_DATE() - 优化后:
rq.QueueDate >= CURRENT_DATE() AND rq.QueueDate < DATE_ADD(CURRENT_DATE(), INTERVAL 1 DAY)
3. 添加针对性索引
给关联字段和筛选字段创建复合索引,让MySQL能快速定位数据:
- 给
regist_queue创建:INDEX idx_rq_token_loc_date (token_number, LocationId, QueueDate) - 给
appoint创建:INDEX idx_ap_ticket_loc_date_pat (daily_ticket_no, LocationId, dAppDate, iPatID) - 给
patient创建:INDEX idx_pr_patid (IPatID)
修改后的查询语句示例
SELECT * FROM regist_queue rq LEFT JOIN appoint ap ON rq.token_number = ap.daily_ticket_no AND ap.LocationId = 15800 AND ap.dAppDate >= CURRENT_DATE() AND ap.dAppDate < DATE_ADD(CURRENT_DATE(), INTERVAL 1 DAY) LEFT JOIN patient pr ON ap.iPatID = pr.IPatID -- 这里补充你剩下的JOIN语句 WHERE rq.LocationId = 15800 AND rq.QueueDate >= CURRENT_DATE() AND rq.QueueDate < DATE_ADD(CURRENT_DATE(), INTERVAL 1 DAY);
4. 验证执行计划
修改后可以用EXPLAIN命令查看执行计划,确认是否用到了预期的索引,避免出现type: ALL(全表扫描)的情况。
内容的提问来源于stack exchange,提问作者Ammar Muhi ud din
相关产品推荐
相关产品推荐

