mysql中ORDER BY的優(yōu)化,直接影響查詢性能,尤其是在數(shù)據(jù)量大的情況下。要提升排序效率,關(guān)鍵在于減少不必要的數(shù)據(jù)掃描和避免臨時(shí)表、文件排序這些高開(kāi)銷操作。
1. 確保使用索引進(jìn)行排序
最直接的優(yōu)化方式是讓ORDER BY走索引,這樣就能跳過(guò)昂貴的文件排序(filesort)過(guò)程。
要滿足這個(gè)條件,需要:
- ORDER BY字段上有索引;
- 查詢的WHERE條件和ORDER BY使用的字段盡量在同一個(gè)索引中;
- 如果是聯(lián)合排序(多個(gè)字段),則要確保使用的是前綴索引。
比如有這樣一個(gè)索引:(status, create_time),那么以下SQL是可以命中索引排序的:
但如果是這樣:
SELECT * FROM orders ORDER BY status, create_time;
雖然排序字段都在索引里,但如果WHERE條件沒(méi)用到,可能也不會(huì)使用索引排序,具體還要看執(zhí)行計(jì)劃(EXPLAIN)的結(jié)果。
2. 避免SELECT *
很多人喜歡寫(xiě)SELECT *,但在帶排序的查詢中,這可能會(huì)導(dǎo)致MySQL必須回表查數(shù)據(jù),甚至放棄索引排序。
建議做法是:
- 只查詢必要的字段;
- 如果排序字段和查詢字段都能包含在一個(gè)覆蓋索引中,那就可以直接從索引中取數(shù)據(jù),不需要回表,效率更高。
舉個(gè)例子,如果你有索引 (user_id, create_time),并且只需要這兩個(gè)字段:
SELECT user_id, create_time FROM users ORDER BY create_time DESC LIMIT 10;
這種情況很可能走覆蓋索引,速度會(huì)比SELECT *快很多。
3. 控制LIMIT范圍,減少排序量
如果只是分頁(yè)展示數(shù)據(jù),不要一次性排好全部再取一部分。應(yīng)盡早限制結(jié)果集大小,例如:
SELECT id, name FROM users ORDER BY score DESC LIMIT 100, 10;
這里雖然還是要做排序,但至少只排了110條數(shù)據(jù)而不是全表。
注意:深分頁(yè)(如LIMIT 100000, 10)會(huì)導(dǎo)致性能下降,可以考慮使用“游標(biāo)分頁(yè)”來(lái)替代。
4. 合理設(shè)置排序緩沖區(qū)(sort_buffer_size)
當(dāng)無(wú)法使用索引排序時(shí),MySQL會(huì)使用sort_buffer_size來(lái)處理內(nèi)存中的排序。
這個(gè)值默認(rèn)比較小,如果你的應(yīng)用中有大量需要排序的查詢,可以適當(dāng)調(diào)大該參數(shù)(通常設(shè)為1M~4M),但不要太大,否則容易浪費(fèi)內(nèi)存資源。
可以通過(guò)SHOW STATUS LIKE ‘Sort%’;查看排序相關(guān)的統(tǒng)計(jì)信息,觀察是否頻繁使用磁盤(pán)排序(Sort_merge_passes太高說(shuō)明內(nèi)存不足)。
基本上就這些。優(yōu)化ORDER BY的核心就是盡可能利用索引、減少排序數(shù)據(jù)量、控制查詢字段,再加上一點(diǎn)配置調(diào)整,大多數(shù)場(chǎng)景都能搞定。