MySQL Inner Join COUNT查询性能优化求助:SQL执行耗时3分钟
SQL查询优化方案(耗时3分钟)
原查询语句
select COUNT(b.register_no) from table1 a INNER JOIN table2 b ON a.register_no = b.register_no INNER JOIN table3 c ON a.register_no = c.register_no AND b.card_no = c.card_no;
基础信息
- 各表数据量:Table1有200万条数据,Table2有250万条数据,Table3有400万条数据
- 执行计划(EXPLAIN):
| 表名 | 类型 | 额外信息 |
|---|---|---|
| table2 | index | 使用条件;使用索引 |
| table3 | ref | 使用条件 |
| table1 | eq_ref | 使用索引 |
1. 优化索引策略
- 给
table2创建联合索引(register_no, card_no):当前执行计划显示table2是全索引扫描,这个联合索引可以让查询直接通过register_no匹配关联条件,同时后续和table3关联时能直接用索引里的card_no过滤,避免全索引遍历,实现覆盖索引查询。 - 给
table3创建联合索引(register_no, card_no):和table2的索引逻辑一致,让a.register_no = c.register_no和b.card_no = c.card_no两个关联条件都能命中索引,提升匹配效率。 - 确认
table1的register_no是主键或唯一索引(执行计划显示eq_ref,大概率已满足),保证关联时的快速定位。
2. 调整关联逻辑与顺序
- 尝试先关联数据量较小的表,缩小中间结果集后再关联大表,比如先关联table1和table2,再和table3关联:
SELECT COUNT(t.register_no) FROM ( SELECT b.register_no, b.card_no FROM table1 a INNER JOIN table2 b ON a.register_no = b.register_no ) t INNER JOIN table3 c ON t.register_no = c.register_no AND t.card_no = c.card_no;
- 如果table2和table3中
register_no+card_no的重复数据较多,可以先对这两个表去重再关联,减少关联次数(注意:如果业务需要统计所有匹配行数,不要加DISTINCT):
SELECT COUNT(b.register_no) FROM table1 a INNER JOIN (SELECT DISTINCT register_no, card_no FROM table2) b ON a.register_no = b.register_no INNER JOIN (SELECT DISTINCT register_no, card_no FROM table3) c ON a.register_no = c.register_no AND b.card_no = c.card_no;
3. 更新表统计信息
- 执行
ANALYZE TABLE table1, table2, table3;(以MySQL为例),更新数据库的表统计信息,让优化器能生成更精准的执行计划,避免因为统计信息过时导致的低效关联顺序。
4. 验证计数逻辑
- 确认是否需要统计所有匹配的行数,还是只需要统计唯一的
register_no数量。如果是后者,直接用COUNT(DISTINCT b.register_no)替代COUNT(b.register_no),可以减少计数时的运算量(前提是业务逻辑允许)。
内容的提问来源于stack exchange,提问作者KillerTwo
相关产品推荐
相关产品推荐

