COUNT 查询优化深度解析
候选人小张在阿里 P6 面试中,面试官问:
"SELECT COUNT(*) FROM orders WHERE status = 1 执行很慢,怎么优化?"
小张说:"可以加索引。"
面试官追问:"加了索引还是慢怎么办?"
小张说:"...那就用缓存?"
面试官继续追问:"COUNT(*) 和 COUNT(1) 有什么区别?"
小张答不上来了。
【面试官心理】 这道题我用来测试候选人对 COUNT 执行原理的理解深度。能说出加索引的占 60%,能讲清 COUNT 原理的占 20%,能提出完整优化方案的占 10%。
一、COUNT(*) 的执行原理 🔴
1.1 COUNT(*) 的语义
1.2 InnoDB 的 COUNT(*) 实现
MySQL InnoDB 执行 COUNT(*) 的过程:
1.3 不同 COUNT 的区别
1.4 ❌ 错误理解
候选人原话:"COUNT(*) 会把每行数据都读取出来,所以慢。"
问题诊断:
- 不理解 InnoDB 用的是计数器,不是真的读数据
- 但扫描行数确实很多,这就是慢的原因
二、COUNT 慢的原因 🔴
2.1 全表扫描
MySQL 需要扫描 500 万行才能得到结果。
2.2 索引扫描
索引扫描只扫描满足条件的行,不需要回表。
三、优化方案 🟡
3.1 方案一:覆盖索引
Using index 表示完全在索引中完成,不需要回表。
3.2 方案二:维护计数器
3.3 方案三:Redis 计数器
3.4 方案四:异步统计
四、不同 COUNT 场景的选择 🟡
4.1 精确计数
4.2 近似计数
4.3 去重计数
五、生产避坑 🟡
5.1 COUNT(*) 和 COUNT(column) 的坑
5.2 COUNT(*) 在 InnoDB 和 MyISAM 的区别
5.3 监控 COUNT 查询
【面试官心理】 能说出 MyISAM 和 InnoDB 在 COUNT 上差异的候选人,基本都理解两种存储引擎的区别。这是 P6 的水准。
六、面试追问链 🟡
第一层:COUNT(*) 怎么执行的?
- 候选人:扫描行,计数
第二层:COUNT(*) 和 COUNT(1) 区别?
- 候选人:几乎一样,优化器会优化
第三层:COUNT(*) 在 MyISAM 和 InnoDB 的区别?
- 候选人:MyISAM 有专门计数器,InnoDB 需要扫描
第四层:怎么优化 COUNT 查询?
- 候选人:覆盖索引、维护计数器、Redis