ORDER BY ... LIMIT M 是 SQL 優化常見場景,核心原理是利用索引有序性,優化器沿著索引順序掃描,掃到滿足條件的 M 行即停止。但實務中常見未善用此特性導致效能不佳,以下透過兩個實際案例說明。
SELECT * FROM test_order_desc
WHERE END_TIME > NOW()
ORDER BY GMT_CREATE DESC, count_num DESC
LIMIT 12, 12;
執行時間:0.49 秒,掃描 113,549 行,出現 Using filesort。
EXPLAIN 结果:
type=range, key=ind_hot_endtime, rows=113549, Extra=Using where; Using filesort
現有索引 ind_hot_endtime(end_time, count_num) 可用於過濾,但無法支援 ORDER BY gmt_create, count_num,導致大量資料需在記憶體/磁碟排序。
ALTER TABLE test_order_desc
ADD INDEX ind_gmt_create(gmt_create, count_num);
type=index, key=ind_gmt_create, rows=48, Extra=Using whereSELECT b.*, a.*, k.*
FROM instance b
LEFT JOIN image a ON b.image_id = a.image_id
LEFT JOIN key_pair k ON b.key_pair_id = k.key_pair_id
LEFT JOIN region_alias r_a ON r_a.region_no = b.region_no
WHERE b.STATUS IN (1,8)
AND b.user_id = 21
AND r_a.big_region_no = 'region_xx'
ORDER BY b.instance_no ASC
LIMIT 37300, 50;
執行時間:**1.28 秒**
STATUS IN (1,8) 導致 instance_no 索引失效,產生臨時表排序ALTER TABLE instance
ADD INDEX ind_user_id(user_id, instance_no);
EXPLAIN SELECT ...
FROM instance b FORCE INDEX (ind_user_id)
LEFT JOIN ...
ORDER BY b.instance_no ASC LIMIT 37300, 50;
| 方案 | 掃描行數 | 執行時間 |
|---|---|---|
| 原始 | — | 1.28 秒 |
| 新增索引 + FORCE INDEX | 54,580 | 0.49 秒 |
WHERE 過濾與 ORDER BY 排序,配合 LIMIT 早期終止掃描