面试题答案
一键面试优化方面
- 分析查询语句:
- 仔细审查
SELECT
、JOIN
、WHERE
、GROUP BY
、HAVING
和ORDER BY
子句,明确查询的核心需求。例如,确定哪些字段用于过滤数据(WHERE
子句中的条件字段),哪些字段用于分组或排序。 - 利用
EXPLAIN
关键字分析查询执行计划,查看查询中表的连接顺序、使用的索引情况等。例如,如果EXPLAIN
结果显示某个表使用了全表扫描(type
为ALL
),则需要考虑为相关字段添加合适索引。
- 仔细审查
- 索引优化:
- 创建合适索引:
- 针对
WHERE
子句中的条件字段,如果这些字段没有索引,考虑创建索引。例如,对于WHERE column1 = 'value'
,若column1
无索引,可创建CREATE INDEX idx_column1 ON table_name (column1);
。 - 对于多表
JOIN
,确保连接字段上有索引。比如JOIN table2 ON table1.id = table2.table1_id
,table1.id
和table2.table1_id
应创建索引。 - 对于
GROUP BY
和ORDER BY
子句中的字段,如果性能不佳,也可考虑创建索引。但要注意,复合索引的顺序很重要,一般按照查询中字段的使用顺序来创建。例如,ORDER BY column1, column2
,可创建CREATE INDEX idx_column1_column2 ON table_name (column1, column2);
- 针对
- 避免冗余和低效索引:检查是否存在冗余索引(即功能重复的索引),可通过分析索引的覆盖范围来判断。例如,如果有索引
idx1 (column1, column2)
和idx2 (column1)
,在查询中idx2
未单独发挥作用时,idx2
可能是冗余的,可以删除。同时,避免创建过度复杂且很少使用的索引,因为索引维护也会消耗资源。
- 创建合适索引:
- 表结构优化:
- 范式与反范式:检查表结构是否过度范式化或反范式化。过度范式化可能导致过多的表连接,增加查询复杂度;过度反范式化可能导致数据冗余和更新异常。例如,如果有频繁查询需要关联多个高度范式化的表,可以适当进行反范式化,将部分常用字段冗余到一个表中,但要权衡更新操作的成本。
- 分区表:如果表数据量非常大,可以考虑使用分区表。根据数据的某个特性(如时间、ID范围等)将表分成多个分区。例如,按时间分区,每月的数据存放在一个分区中,查询时可以快速定位到相关分区,减少扫描的数据量。
- 查询重写:
- 等价改写:通过逻辑等价的方式改写查询语句,使其执行效率更高。例如,对于
NOT IN
子查询,可以尝试改写成LEFT JOIN
+IS NULL
的形式。如原查询SELECT * FROM table1 WHERE id NOT IN (SELECT id FROM table2);
可改写为SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id = table2.id WHERE table2.id IS NULL;
- 使用临时表:对于复杂的子查询或中间结果集,可以考虑使用临时表。先将中间结果计算出来并存入临时表,后续查询直接从临时表获取数据,减少重复计算。但要注意临时表的创建和销毁时机,避免过多占用资源。
- 等价改写:通过逻辑等价的方式改写查询语句,使其执行效率更高。例如,对于
利用索引统计数据缓存辅助优化
- 了解索引统计信息:MySQL 的索引统计数据缓存保存了关于索引的统计信息,如索引基数(不同值的数量)、页面分布等。通过查询
information_schema.statistics
视图,可以获取这些统计信息。例如,SELECT index_name, cardinality FROM information_schema.statistics WHERE table_schema = 'your_database' AND table_name = 'your_table';
中的cardinality
字段表示索引基数,基数越大,索引的选择性越好,查询性能可能越高。 - 索引维护与更新:基于索引统计信息,判断是否需要对索引进行维护操作。如果发现某个索引的基数发生了较大变化(如数据大量插入或删除后),可能需要重新统计索引信息。可以使用
ANALYZE TABLE
语句来更新索引统计数据缓存,例如ANALYZE TABLE your_table;
这有助于优化器更准确地选择执行计划。 - 优化器提示:在某些情况下,了解索引统计数据缓存后,可以使用优化器提示来强制优化器使用特定索引。例如,
SELECT /*+ INDEX(table_name idx_column1) */ * FROM table_name WHERE column1 = 'value';
通过这种方式,利用索引统计信息引导优化器使用最合适的索引,提高查询性能。