# 怎么從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(N2)降低到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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。