LeetCode MySQL刷题指南:从入门到精通
1. 为什么选择LeetCode刷MySQL题?
作为一名数据库工程师,我最初接触LeetCode的MySQL题库纯粹是为了应付面试。但真正坚持刷了三个月后,发现这套题库的价值远超预期——它系统性地覆盖了SQL语言90%以上的核心知识点,特别是那些实际工作中容易忽略的边界场景。
LeetCode的MySQL题库目前有约150道题目,按难度分为简单、中等和困难三个级别。与其他刷题平台相比,它的特色在于:
- 每道题都提供真实的数据表结构和测试用例
- 支持在线编写SQL并即时验证结果
- 题目描述模拟了真实业务场景的需求
- 讨论区有大量优质解法可以参考
提示:建议从「简单」难度开始建立信心,但不要长期停留在舒适区。我个人的经验是,连续刷20道简单题后就应该挑战中等难度。
2. 刷题前的环境准备
2.1 本地MySQL环境配置
虽然LeetCode提供在线执行环境,但本地搭建MySQL环境能让你更自由地测试各种写法。推荐使用Docker快速部署:
docker run --name leetcode-mysql -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql:8.0安装完成后,建议配置:
- 设置SQL模式为严格模式(避免宽松模式下的隐式转换)
SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES';- 创建专用数据库
CREATE DATABASE leetcode CHARACTER SET utf8mb4;2.2 数据导入技巧
LeetCode每道题都会给出类似这样的表结构:
CREATE TABLE Employees ( id INT PRIMARY KEY, name VARCHAR(50), department VARCHAR(50), salary INT );我开发了一个Python脚本自动生成测试数据(完整代码见附录):
- 根据字段类型生成合理值
- 确保外键关联正确
- 制造边界条件数据(如NULL值)
3. 核心解题方法论
3.1 四步分析法
面对任何SQL题目,我都遵循以下步骤:
需求拆解:用红笔圈出题目中的关键条件
- 示例:找出"薪资高于部门平均值"的员工
- 隐含需求:需要先计算每个部门的平均薪资
表关系分析:绘制ER图理清连接关系
- 自连接的特殊处理
- 多表连接的顺序选择
执行计划预判:EXPLAIN分析可能的性能瓶颈
- 重点关注type列(最好到range级别)
- 注意Using filesort和Using temporary
边界测试:验证极端情况
- NULL值处理
- 空表情况
- 重复数据
3.2 高频考点精讲
3.2.1 窗口函数实战
窗口函数是中等难度以上的必考内容。以经典题目「部门工资前三高的员工」为例:
SELECT Department, Employee, Salary FROM ( SELECT d.name AS Department, e.name AS Employee, e.salary AS 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 ) t WHERE rnk <= 3;注意:区分RANK()、DENSE_RANK()和ROW_NUMBER()的使用场景:
- RANK():并列排名会跳过后续序号(1,2,2,4)
- DENSE_RANK():并列排名不跳号(1,2,2,3)
- ROW_NUMBER():强制连续编号(1,2,3,4)
3.2.2 递归CTE应用
处理树形结构数据时,递归CTE是终极武器。比如「员工层级关系查询」:
WITH RECURSIVE EmpHierarchy AS ( -- 基础查询:找出CEO SELECT id, name, managerId, 1 AS level FROM Employee WHERE managerId IS NULL UNION ALL -- 递归查询:逐级向下查找 SELECT e.id, e.name, e.managerId, eh.level + 1 FROM Employee e JOIN EmpHierarchy eh ON e.managerId = eh.id ) SELECT * FROM EmpHierarchy;4. 性能优化进阶
4.1 索引设计原则
根据题目特点创建合适的索引:
- 高频过滤条件列建单列索引
- 多列条件考虑组合索引
- 注意最左前缀原则
-- 题目:频繁按部门和薪资范围查询 ALTER TABLE Employees ADD INDEX idx_dept_salary (department, salary);4.2 执行计划深度解析
以「查找没有订单的客户」为例,对比两种写法:
写法A:NOT IN
EXPLAIN SELECT name FROM Customers WHERE id NOT IN (SELECT customerId FROM Orders);写法B:LEFT JOIN
EXPLAIN SELECT c.name FROM Customers c LEFT JOIN Orders o ON c.id = o.customerId WHERE o.id IS NULL;执行计划关键指标对比:
| 指标 | NOT IN | LEFT JOIN |
|---|---|---|
| type | ALL | eq_ref |
| rows | 全表扫描 | 索引查找 |
| Extra | Using where | Using where; Not exists |
5. 错题本管理技巧
我维护的错题本包含以下维度:
题目分类
- 连接查询
- 子查询
- 聚合函数
- 日期处理
- 字符串处理
错误原因
- 语法错误(30%)
- 逻辑错误(50%)
- 性能问题(20%)
改进方案
- 重写SQL
- 添加索引
- 修改表结构
示例记录:
题目:第N高的薪水 错误:忽略了NULL处理 修正:使用IFNULL包装结果6. 刷题路线建议
根据三个月刷完所有题目的经验,推荐如下节奏:
| 阶段 | 目标 | 时间 | 重点 |
|---|---|---|---|
| 入门 | 简单题50道 | 2周 | 基础语法 |
| 进阶 | 中等题80道 | 4周 | 复杂查询 |
| 攻坚 | 困难题20道 | 2周 | 性能优化 |
| 复习 | 错题重做 | 持续 | 查漏补缺 |
每日建议:
- 新题3道(含至少1道中等)
- 复习错题5道
- 每周总结一次知识图谱
7. 实战案例解析
7.1 连续登录问题
题目:查找连续登录至少5天的用户
解决方案:
SELECT DISTINCT a.user_id FROM Logins a JOIN Logins b ON a.user_id = b.user_id AND DATEDIFF(b.login_date, a.login_date) BETWEEN 1 AND 4 GROUP BY a.user_id, a.login_date HAVING COUNT(DISTINCT b.login_date) = 4;优化思路:
- 在user_id和login_date上创建组合索引
- 使用窗口函数替代自连接(MySQL 8.0+)
7.2 留存率计算
题目:计算次日留存率
SELECT ROUND( COUNT(DISTINCT b.user_id) / COUNT(DISTINCT a.user_id), 2 ) AS retention_rate FROM (SELECT DISTINCT user_id FROM Logins WHERE date = '2023-01-01') a LEFT JOIN (SELECT DISTINCT user_id FROM Logins WHERE date = '2023-01-02') b ON a.user_id = b.user_id;8. 附录:实用工具脚本
8.1 测试数据生成器
import random import pymysql def generate_employees(count=100): departments = ['HR', 'Engineering', 'Marketing', 'Finance'] conn = pymysql.connect(host='localhost', user='root', password='123456', database='leetcode') with conn.cursor() as cursor: for i in range(1, count+1): name = f'Employee_{i}' dept = random.choice(departments) salary = random.randint(3000, 15000) cursor.execute( "INSERT INTO Employees VALUES (%s, %s, %s, %s)", (i, name, dept, salary) ) conn.commit()8.2 执行计划可视化工具
使用MySQL Workbench的Visual Explain功能,可以图形化查看执行计划:
- 编写查询语句
- 点击"Execution Plan"标签
- 分析各节点的成本占比
9. 面试高频考点
根据近期面试经验整理的高频考点:
JOIN原理
- Nested Loop Join实现机制
- Hash Join的适用场景
索引优化
- 最左前缀原则实例
- 覆盖索引的优势
事务隔离
- 脏读/幻读的复现
- MVCC实现原理
分库分表
- 水平拆分策略
- 分布式ID生成方案
10. 持续提升建议
完成LeetCode题库后,建议向这些方向深入:
MySQL源码研究
- 查询优化器工作流程
- InnoDB存储引擎架构
性能基准测试
- sysbench压力测试
- 慢查询日志分析
分布式数据库
- 主从复制原理
- 分片集群部署
云数据库实践
- RDS参数调优
- 读写分离配置
我个人的学习路径是:LeetCode刷题 → 《高性能MySQL》→ MySQL源码调试 → 分布式方案实践。每个阶段都需要用实际项目验证理论,才能真正消化知识。