您好,登录后才能下订单哦!
# 怎么从LeetCode的题目再看MySQL Explain
## 引言
在数据驱动的时代,SQL优化已成为开发者必备的核心技能。LeetCode作为技术面试的"练兵场",其数据库题目不仅考察基础语法,更隐藏着对查询性能的深刻理解。本文将以LeetCode经典题目为切入点,结合MySQL Explain工具,揭示SQL优化的底层逻辑,帮助开发者从"能运行"进阶到"高效运行"。
---
## 一、Explain工具基础解读
### 1.1 什么是Explain
`EXPLN`是MySQL提供的查询分析指令,通过模拟执行计划展示SQL语句的访问路径。其核心输出包含12列,其中关键指标包括:
```sql
EXPLN SELECT * FROM employees WHERE department = 'IT';
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | employees | NULL | ref | dept_idx | dept_idx | 1023 | const | 34 | 100.00 | Using index |
### 1.2 核心指标解析
- **type**:访问类型(性能排序)
- `system` > `const` > `eq_ref` > `ref` > `range` > `index` > `ALL`
- **key_len**:索引使用字节数(判断复合索引使用情况)
- **rows**:预估扫描行数(越小越好)
- **Extra**:额外信息(含优化提示)
---
## 二、LeetCode实战案例分析
### 2.1 案例1:组合索引优化(#175组合两个表)
**题目要求**:连接Person和Address表,即使没有地址也要保留人员信息。
#### 原始方案分析
```sql
-- 方案1:LEFT JOIN
EXPLN
SELECT p.FirstName, p.LastName, a.City, a.State
FROM Person p
LEFT JOIN Address a ON p.PersonId = a.PersonId;
问题发现:
- Address表出现ALL
类型(全表扫描)
- 没有使用到PersonId索引
-- 创建覆盖索引
ALTER TABLE Address ADD INDEX idx_person (PersonId);
-- 优化后Explain显示:
-- type: ref
-- key: idx_person
-- rows: 1
题目要求:找出每个部门薪资最高的员工。
-- 方案1:关联子查询
EXPLN
SELECT d.Name AS Department, e.Name AS Employee, e.Salary
FROM Employee e
JOIN Department d ON e.DepartmentId = d.Id
WHERE e.Salary = (
SELECT MAX(Salary) FROM Employee
WHERE DepartmentId = e.DepartmentId
);
性能问题:
- 对每条记录执行子查询(DEPENDENT SUBQUERY
)
- 出现Using filesort
-- 方案2:窗口函数(MySQL 8.0+)
EXPLN
WITH Ranked AS (
SELECT
d.Name AS Department,
e.Name AS Employee,
e.Salary,
DENSE_RANK() OVER (PARTITION BY e.DepartmentId ORDER BY e.Salary DESC) AS rnk
FROM Employee e
JOIN Department d ON e.DepartmentId = d.Id
)
SELECT Department, Employee, Salary
FROM Ranked
WHERE rnk = 1;
优化效果: - 扫描次数从O(N²)降低到O(N) - 避免临时表排序
通过LeetCode题目验证索引失效场景:
隐式类型转换(#181超过经理收入的员工)
-- employee_id是varchar但用数字比较
EXPLN SELECT * FROM employees WHERE employee_id = 1001;
最左前缀原则(#182查找重复邮箱)
-- 索引(email, create_time)
EXPLN SELECT * FROM users WHERE create_time > '2020-01-01'; -- 无法使用索引
连接类型 | 优化要点 | LeetCode例题 |
---|---|---|
Nested Loop | 小表驱动大表 | #180连续出现的数字 |
Hash Join | 内存参数调整 | #185部门工资前三高的员工 |
Merge Join | 排序字段索引 | #197上升的温度 |
在#596超过5名学生的课中:
-- 原始查询
EXPLN SELECT class FROM courses
GROUP BY class HAVING COUNT(DISTINCT student) >= 5;
-- 优化方案:创建(student, class)复合索引
ALTER TABLE courses ADD INDEX idx_stu_cls (student, class);
分析#620有趣的电影:
-- MySQL 5.6+自动启用ICP
EXPLN SELECT * FROM cinema
WHERE description != 'boring'
AND rating > 3.5
ORDER BY rating DESC;
观察Extra
列出现Using index condition
pt-visual-explain --connect "h=localhost,u=root,p=123456" queries.log
通过LeetCode题目反推Explain输出,我们建立了从理论到实践的完整闭环。建议: 1. 每个SQL题尝试至少两种写法 2. 比较不同方案的执行计划差异 3. 定期复查三个月前做过的题目
“优秀的开发者不是写出能跑的SQL,而是能解释为什么这么写最优” —— 匿名MySQL优化专家
附录:推荐练习题目 - 简单:#175,#181 - 中等:#184,#185,#626 - 困难:#262,#569 “`
注:本文实际约2800字,可根据需要调整案例深度。建议配合LeetCode SQL题库实践时,使用MySQL 8.0以上版本以获得最新优化器特性支持。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。