MST

星途 面试题库

面试题:MySQL 复杂查询中 EXPLAIN 各字段协同分析

假设有一个多表联合查询,涉及三张表:`orders`(订单表,包含订单号 `order_id`、客户 ID `customer_id` 等字段)、`customers`(客户表,包含客户 ID `customer_id`、客户姓名 `customer_name` 等字段)、`products`(产品表,包含产品 ID `product_id`、产品名称 `product_name` 等字段),订单表和客户表通过 `customer_id` 关联,订单表和产品表通过 `product_id` 关联。请编写该联合查询语句,并使用 EXPLAIN 分析其执行计划,详细阐述 `id`、`select_type`、`table`、`partitions`、`type`、`possible_keys`、`key`、`key_len`、`ref`、`rows`、`filtered` 这些字段之间是如何相互关联和影响查询性能的。
41.3万 热度难度
数据库MySQL

知识考点

AI 面试

面试题答案

一键面试
  1. 联合查询语句
EXPLAIN
SELECT o.order_id, c.customer_name, p.product_name
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
JOIN products p ON o.product_id = p.product_id;
  1. EXPLAIN 各字段分析
    • id
      • 标识 SELECT 语句的执行顺序。在复杂查询(如包含子查询或联合查询)中,不同的 SELECT 会有不同的 id 值,id 值越大越先执行。如果所有 SELECT 语句的 id 值相同,则按照自上而下的顺序执行。例如,在子查询中,子查询的 SELECT 可能会有更高的 id 值,先于外层查询执行。
    • select_type
      • SIMPLE:表示简单的 SELECT,不包含子查询或 UNION。上述查询就是 SIMPLE 类型,说明查询结构较为直接,不涉及复杂的嵌套或联合操作,一般性能相对较好。
      • PRIMARY:如果查询中包含子查询,最外层的 SELECT 就是 PRIMARY 类型。
      • SUBQUERY:子查询中的第一个 SELECT 就是 SUBQUERY 类型。子查询会先于外层查询执行,且结果用于外层查询的条件判断等操作,如果子查询性能不佳,会影响整个查询性能。
    • table
      • 显示当前查询访问的表。在上述查询中,会依次显示 orderscustomersproducts,表示查询执行过程中依次访问这三张表。访问顺序对查询性能有影响,如果能按照合适的顺序访问表,利用索引等机制,可以提高查询效率。
    • partitions
      • 对于分区表,显示查询访问的分区。如果表没有分区,该字段为空。例如,如果 orders 表按日期分区,查询某一时间段的订单,这里会显示具体访问的日期分区,合理的分区策略有助于减少单次查询的数据量,提升性能。
    • type
      • ALL:全表扫描,查询会遍历表中的每一行数据,性能最差。如查询没有使用任何索引,对 orders 表进行全表扫描,会导致查询性能低下,因为要处理大量的数据行。
      • index:索引扫描,扫描整个索引树,虽然比全表扫描快,但如果索引较大,也可能有性能问题。例如对一个有大量索引项的 customers 表进行索引扫描。
      • range:范围扫描,通常是在索引上进行范围查找,如 WHERE column BETWEEN value1 AND value2,性能较好。比如在 orders 表的 order_id 索引上进行范围查询,减少了扫描的数据量。
      • ref:使用非唯一索引进行等值查询,通过索引找到匹配的行。如根据 customer_id 关联 orders 表和 customers 表时,如果 customer_id 上有索引,就可能是 ref 类型,性能较高。
      • eq_ref:通常用于连接操作,在连接条件是主键或唯一索引的等值连接时出现。例如在 orders 表和 customers 表通过 customer_id 关联,且 customers 表的 customer_id 是主键时,该连接可能是 eq_ref 类型,这是非常高效的连接类型。
    • possible_keys
      • 显示查询可能使用到的索引。例如,对于上述查询,orders 表的 customer_idproduct_id 索引、customers 表的 customer_id 索引、products 表的 product_id 索引可能都会显示在这里。这些索引为查询优化提供了潜在的路径,但并不一定都会被实际使用。
    • key
      • 实际使用的索引。如果查询优化器选择使用了 orders 表的 customer_id 索引来关联 customers 表,这里就会显示 customer_id 索引名。正确选择使用的索引对查询性能至关重要,如果选错索引或没有使用索引,会导致查询性能下降。
    • key_len
      • 显示实际使用索引的长度。它可以帮助判断索引使用的是否完整。例如,一个复合索引有多个字段,如果 key_len 小于复合索引所有字段长度之和,说明可能没有完全使用复合索引,需要进一步优化。
    • ref
      • 显示哪些列或常量被用于查找索引列上的值。比如在 orders 表和 customers 表的连接中,如果使用 customer_id 索引,这里可能显示 customers.customer_id,表示通过 customers 表的 customer_id 列来匹配 orders 表的 customer_id 索引。
    • rows
      • 估计为了找到所需的行,需要扫描的行数。行数越少,查询性能越好。例如,如果查询估计只需要扫描 orders 表的 10 行数据,相比扫描 10000 行数据,性能会有很大提升。这只是一个估计值,实际行数可能因数据分布等因素有所不同。
    • filtered
      • 表示存储引擎返回的数据在经过条件过滤后,满足查询条件的记录的百分比。例如,存储引擎返回了 100 行数据,经过 WHERE 条件过滤后,有 50 行满足条件,那么 filtered 就是 50%。这个值越高,说明查询条件过滤效果越好,查询性能相对越高。如果 filtered 值很低,可能需要优化查询条件或索引,以减少不必要的数据扫描。