面试题答案
一键面试MySQL执行计划分析
- 全表扫描:如果
age
和salary
字段上均没有索引,MySQL可能会对users
表进行全表扫描。它会逐行读取表中的数据,检查每一行数据的age
是否大于30且salary
是否小于50000,这种方式在数据量较大时性能较差。 - 使用索引:
- 单索引情况:
- 如果只有
age
字段上有索引,MySQL可能会先使用age
索引找到满足age > 30
的记录,然后再对这些记录逐行检查salary < 50000
条件,这可能比全表扫描快,但对于满足age > 30
记录较多时,后续检查salary
条件开销仍较大。 - 同理,如果只有
salary
字段上有索引,MySQL可能先通过salary
索引找到满足salary < 50000
的记录,再逐行检查age > 30
条件。
- 如果只有
- 复合索引情况:如果有复合索引
(age, salary)
,MySQL可以利用该复合索引快速定位到满足age > 30
且salary < 50000
的记录。因为复合索引是先按age
排序,在age
相同的情况下再按salary
排序,所以可以快速过滤出符合条件的数据,性能较好。
- 单索引情况:
优化方法
- 优化索引:
- 创建复合索引:可以创建复合索引
CREATE INDEX idx_age_salary ON users(age, salary);
。这样MySQL在执行查询时,能更有效地利用索引快速定位满足两个条件的数据,减少数据扫描量。在复合索引中,字段顺序很重要,这里将age
放在前面是因为查询条件中age
在前,MySQL会优先使用最左前缀原则匹配索引。 - 避免冗余索引:避免创建不必要的索引,因为索引本身会占用额外的存储空间,并且在数据插入、更新和删除时,MySQL需要更新索引,增加额外的开销。例如,已经有了
(age, salary)
复合索引,就没必要再单独创建age
或salary
的单索引(除非有其他查询场景有单独使用age
或salary
索引的需求)。
- 创建复合索引:可以创建复合索引
- 优化查询语句:
- 确保查询条件简洁:确保查询条件没有不必要的函数调用或复杂的表达式。例如,如果查询条件写成
SELECT * FROM users WHERE UPPER(name) = 'JOHN' AND age > 30 AND salary < 50000;
,由于UPPER(name)
函数调用,MySQL无法使用name
字段上的索引(如果有的话),会导致性能下降。应尽量避免这种情况,保持查询条件简单直接。 - 合理使用覆盖索引:如果查询只需要部分字段,如
SELECT age, salary FROM users WHERE age > 30 AND salary < 50000;
,并且创建了(age, salary)
复合索引,MySQL可以直接从索引中获取数据,而不需要回表操作(即从索引找到数据对应的主键,再通过主键去聚簇索引中获取完整数据行),进一步提升性能。可以考虑调整查询,尽量利用覆盖索引。
- 确保查询条件简洁:确保查询条件没有不必要的函数调用或复杂的表达式。例如,如果查询条件写成