相同 SQL,LIMIT 10 耗時 3 分 3 秒,LIMIT 100 耗時 1.24 秒。LIMIT 67 與 LIMIT 68 執行計劃截然不同。
-- LIMIT 67 (慢) id: 1, table: a, type: range, key: B (f1,f2,f3), rows: 2,555,192, Extra: Using where; Using temporary; Using filesort -- LIMIT 68 (快) id: 1, table: a, type: ref, key: A (f3,f4,f1,f2,f5), key_len: 3, ref: const, rows: 67,586, Extra: Using where; Using temporary; Using filesort
(f3, f4, f1, f2, f5)(f1, f2, f3)f3,索引 B 可用 f1(f1,f2,f3) 而非前綴 f1
f1 1000 個值 → 平均 500 行/值(f1,f2,f3) 50 萬值 → 平均 1 行/值LIMIT 值參與代價乘積:LIMIT 較大時,索引 B 代價超過 A,優化器才正確選 AGROUP BY 放大效應:每增加 1 個 LIMIT,實際需掃描 N 行(N = 總行數 / 不同 f2 值)EXPLAIN SELECT ... FORCE INDEX(A) ... LIMIT 67; -- rows: 67,586,證明索引 A 確實更優
修改優化器源碼 test_if_cheaper_ordering 邏輯,計算索引區分度時使用實際可用前綴長度而非完整索引鍵。
FORCE INDEX(A) 強制走正確索引