Using filesort 是 EXPLAIN 中常見的「效能殺手」標誌,表示 MySQL 無法利用索引順序直接返回排序結果,被迫在內存或磁盤進行文件排序。本文通過實戰案例演示如何通過索引消除 Filesort,並深度解析 max_length_for_sort_data 這一隱性限制參數對優化效果的決定性影響。
SELECT * FROM yw_syjgb ORDER BY result_date DESC LIMIT 0, 1000;
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|---|---|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | yw_syjgb | ALL | NULL | NULL | NULL | NULL | 1312418 | Using filesort |
全表掃描 131 萬行 + 文件排序,效能極差。
ALTER TABLE yw_syjgb ADD INDEX idx_result_date (result_date);
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|---|---|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | yw_syjgb | index | NULL | result_date | 6 | NULL | 1000 | (無 Using filesort) |
type=index 表示全索引掃描,但由於索引天然有序,直接按索引順序讀取前 1000 行即可,完全消除 Filesort,rows 從 131 萬降為 1000(LIMIT 推下)。
即使建立了排序列索引,某些場景仍會出現 Filesort。核心原因在於 MySQL 內部排序算法的記錄長度限制。
SHOW VARIABLES LIKE '%max_length_for_sort_data%'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | max_length_for_sort_data | 1024 | -- 默認 1024 字節 +--------------------------+-------+
SELECT * 導致行長度超過 1024 字節,MySQL 強制退回原始模式,若排序數據量大仍會觸發 Filesort| 場景 | 是否觸發 Filesort | 對策 |
|---|---|---|
| SELECT id, result_date FROM t ORDER BY result_date LIMIT 1000 | 否(行長 < 1024) | 優先使用覆蓋索引 |
| SELECT * FROM t ORDER BY result_date LIMIT 1000(含大字段) | 是(行長 > 1024) | 1. 避免 SELECT * 2. 增大 max_length_for_sort_data(如 2048/4096) 3. 拆分大字段到副表 |
| ORDER BY 多列複合索引 | 視索引順序匹配度 | 嚴格遵循最左前綴 + 方向一致 |
INDEX (result_date, col1, col2) 滿足 SELECT col1, col2 FROM t ORDER BY result_date,實現純索引掃描零回表sort_buffer_size(會話級)配合 max_length_for_sort_data 協同調優ORDER BY UPPER(name) 無法用索引,改為函數索引(MySQL 8.0+)或冗餘列WHERE result_date < last_val ORDER BY result_date LIMIT 20 游標模式ORDER BY 消除 Filesort 的核心公式:排序列有索引 + 索引順序滿足排序方向 + 查詢列長度 ≤ max_length_for_sort_data(或使用覆蓋索引)。實戰中切勿盲目加索引,需結合 EXPLAIN 觀察 Extra、key_len、rows 三大指標,並警惕 SELECT * 導致的隱性行長超標陷阱。