MST

星途 面试题库

面试题:MySQL慢查询日志下复杂SQL重写优化

现有一个MySQL数据库,慢查询日志记录了一条包含子查询、聚合函数且数据量较大的SQL语句。给出详细的优化方案,要求重写该SQL语句以提高查询效率,同时阐述优化前后执行计划的差异及原理。
29.6万 热度难度
数据库MySQL

知识考点

AI 面试

面试题答案

一键面试

优化方案

  1. 分析子查询:若子查询是相关子查询,尝试将其改写为连接查询。例如,假设有如下子查询:
SELECT column1, (SELECT COUNT(*) FROM other_table WHERE other_table.id = main_table.id) AS count
FROM main_table;

可改写为连接查询:

SELECT main_table.column1, COUNT(other_table.id) AS count
FROM main_table
LEFT JOIN other_table ON main_table.id = other_table.id
GROUP BY main_table.column1, main_table.id;
  1. 聚合函数优化:如果聚合函数操作的数据量非常大,可以考虑在中间表或索引上进行聚合。例如,对于 SUM 聚合,若数据量巨大,可先创建一个包含预计算 SUM 的中间表,查询时直接从中间表获取数据。
  2. 索引优化
    • 检查查询涉及的列上是否有合适的索引。例如,在上述查询中,如果 main_table.idother_table.id 列没有索引,添加索引:
CREATE INDEX idx_main_table_id ON main_table(id);
CREATE INDEX idx_other_table_id ON other_table(id);
  1. 使用 EXPLAIN 分析:在优化前后分别使用 EXPLAIN 关键字来查看执行计划,根据执行计划进一步调整优化策略。例如:
EXPLAIN SELECT column1, (SELECT COUNT(*) FROM other_table WHERE other_table.id = main_table.id) AS count
FROM main_table;

优化后:

EXPLAIN SELECT main_table.column1, COUNT(other_table.id) AS count
FROM main_table
LEFT JOIN other_table ON main_table.id = other_table.id
GROUP BY main_table.column1, main_table.id;

优化前后执行计划差异及原理

  1. 子查询改连接查询
    • 优化前:子查询可能会导致数据库对外部查询的每一行都执行一次子查询,这是一种嵌套循环的方式,数据量较大时效率很低。例如,外部查询有 n 行,子查询对每一行执行一次,整体复杂度是 O(n * m),其中 m 是子查询结果集行数。
    • 优化后:连接查询通过 JOIN 操作将两个表的数据在一次操作中关联起来,数据库可以使用更高效的算法,如哈希连接或嵌套循环连接(在有合适索引时),整体复杂度可能降低到 O(n + m)
  2. 索引优化
    • 优化前:如果没有索引,数据库在进行表连接或条件筛选时需要全表扫描,这在数据量较大时非常耗时。例如,在上述查询中,如果没有 main_table.idother_table.id 的索引,连接操作需要逐行比较两个表中的 id 列,效率低下。
    • 优化后:添加索引后,数据库可以利用索引快速定位到符合条件的数据行,大大减少了扫描的数据量,提高了查询效率。例如,在连接操作中,通过索引可以快速定位到匹配的 id,而不需要全表扫描。
  3. 聚合函数优化
    • 优化前:对大量数据直接进行聚合操作,数据库需要处理大量数据行,占用较多内存和CPU资源。
    • 优化后:通过中间表或索引上的预计算聚合,查询时只需获取预计算结果,减少了实时计算量,提高了查询效率。