MST
星途 面试题库

面试题:MySQL优化之查询优化器与执行计划

当面对复杂查询时,MySQL的查询优化器会生成多种执行计划,然后选择最优的。请深入分析MySQL查询优化器的工作原理,包括如何解析查询语句、生成执行计划以及成本估算。同时,结合具体的SQL语句,阐述如何通过执行计划分析来优化查询性能,比如如何根据执行计划中的索引使用情况、表连接方式等信息进行优化。
33.5万 热度难度
数据库MySQL

知识考点

AI 面试

面试题答案

一键面试

MySQL查询优化器工作原理

  1. 解析查询语句
    • 词法分析:将输入的SQL语句按字符流解析成一个个的词法单元(token),例如关键字(SELECT、FROM等)、标识符(表名、列名)、操作符(=、+等)等。例如对于SELECT column1 FROM table1 WHERE column2 = 'value';,会把SELECTcolumn1FROM等解析为不同的token。
    • 语法分析:基于词法分析得到的token,依据MySQL的语法规则构建一棵语法树。语法树能清晰地表示查询的逻辑结构,例如根节点可能是SELECT操作,子节点可能是FROM子句对应的表、WHERE子句对应的条件等。
  2. 生成执行计划
    • 逻辑优化:对语法树进行一系列的逻辑变换,以简化查询或使其更易于优化。例如子查询优化,可能会将某些类型的子查询改写为连接查询,从而提高执行效率。对于SELECT * FROM table1 WHERE column1 IN (SELECT column2 FROM table2);,可能会改写为连接形式SELECT table1.* FROM table1 JOIN table2 ON table1.column1 = table2.column2;
    • 物理优化:考虑不同的物理操作实现方式,如不同的表连接算法(嵌套循环连接、哈希连接等),不同的索引使用策略等,生成多个可能的执行计划。例如对于两个表的连接,嵌套循环连接可能会先扫描一个表,然后对该表的每一行去匹配另一个表;哈希连接则会先在内存中构建一个哈希表来加速匹配。
  3. 成本估算
    • I/O成本:主要考虑从磁盘读取数据块的成本。例如,扫描一个大表可能需要多次磁盘I/O操作,成本相对较高;而使用索引能减少磁盘I/O,因为索引通常较小且有序,能快速定位数据。如果表有10000行数据,全表扫描可能需要读取多个数据块,而使用合适的索引可能只需要读取少数几个索引块和对应的数据块。
    • CPU成本:包括比较操作、排序操作等的成本。例如排序大量数据需要消耗较多的CPU资源,在成本估算中会占较大比重。对一个无序的列进行排序,相比对已按该列索引排序的数据进行操作,CPU成本会更高。

通过执行计划分析优化查询性能

假设SQL语句为SELECT orders.order_id, customers.customer_name FROM orders JOIN customers ON orders.customer_id = customers.customer_id WHERE orders.order_date > '2023 - 01 - 01';

  1. 索引使用情况
    • 执行计划查看:在MySQL中,可以使用EXPLAIN关键字查看执行计划。例如执行EXPLAIN SELECT orders.order_id, customers.customer_name FROM orders JOIN customers ON orders.customer_id = customers.customer_id WHERE orders.order_date > '2023 - 01 - 01';。如果执行计划显示Using index,说明使用了索引,这是较好的情况。若显示Using where且没有索引相关信息,可能表示未使用索引。
    • 优化:如果orders表的order_date列没有索引,可考虑创建索引CREATE INDEX idx_order_date ON orders(order_date);。这样在查询时能快速定位满足条件的行,减少扫描的数据量。如果连接条件orders.customer_id = customers.customer_id没有索引,也可在两个表的customer_id列创建索引,提升连接效率。
  2. 表连接方式
    • 执行计划查看:执行计划中会显示连接类型,如ALL(全表扫描连接)、index(索引连接)、range(范围索引连接)等。例如如果显示orders表连接类型为ALL,表示对orders表进行全表扫描来连接。
    • 优化:如果连接类型不理想,可通过调整索引或查询结构来优化。如对于大表连接,若使用嵌套循环连接且驱动表选择不当,可能导致性能问题。可以通过调整连接顺序,让小表作为驱动表,或者使用合适的索引使连接类型变为更高效的indexrange。例如在上述查询中,如果customers表数据量较小,可尝试调整连接顺序先连接customers表,并且确保连接列有索引,提升整体查询性能。