等價(jià)替換left join / right join查詢
多表的left join / right join關(guān)聯(lián)查詢性能較低,可以考慮等價(jià)替換為join的SQL語(yǔ)句或者是用逗號(hào)分隔各個(gè)表,然后用where條件替代on條件作為關(guān)聯(lián)條件的方式,關(guān)聯(lián)查詢多表(目前也推薦用逗號(hào)分隔,where條件替代on條件的方式進(jìn)行多表內(nèi)連接查詢)。
例如對(duì)于同時(shí)符合以下設(shè)定的場(chǎng)景下:
- 如果A表為主表,B為從表。
- 其中,出參包含AB兩個(gè)表的數(shù)據(jù),查詢的條件可能來(lái)源于A,B表。
- A表有記錄,B表未必有記錄。
- B表的code字段與A表的主鍵id字段關(guān)聯(lián)。
- 各個(gè)查詢條件之間是
AND關(guān)系。
那么,查詢SQL語(yǔ)句最直觀地會(huì)寫(xiě)為:
select A.id, B.id from A left join B on A.id=B.code where ……
但是這樣的SQL語(yǔ)句在寬表引擎下并非性能最佳, 可以等價(jià)替換為如下:
- 如果查詢條件來(lái)源于A和B兩表,并且查詢條件都是
AND邏輯拼接。可以改為:
select A.id, B.id from A, B where A.id=B.code and ……
- 如果查詢條件只來(lái)源于A表,可改為使用以下的兩條SQL:
select A.id from A where ……
將以上查詢獲取得到的A表的id傳入到下列B表的SQL,查詢獲取B表的出參。
select B.id from B where B.code=?
- 如果查詢條件只來(lái)源于B表,可以改為使用以下的兩條SQL:
select B.id, B.code from B where ……
將以上查詢獲取得到的B表的code傳入到下列A表的SQL,查詢獲取A表的出參。
select A.id from A where A.id=?
count查詢不應(yīng)該帶order by
count查詢的目的是為了返回符合條件的總記錄數(shù),但是order by則是對(duì)符合條件的記錄進(jìn)行排序,查詢總數(shù)無(wú)需排序,排序則會(huì)增加非必要的耗時(shí),應(yīng)該在count查詢語(yǔ)句中刪除order by。
結(jié)合實(shí)際業(yè)務(wù)場(chǎng)景考慮是否在查詢SQL中帶有order by,count
如果模型中滿足某條件的數(shù)據(jù)量很大,查詢的SQL語(yǔ)句中帶有order by,count過(guò)程非常緩慢??山Y(jié)合自身業(yè)務(wù)場(chǎng)景考慮是否可以放棄。
如果業(yè)務(wù)上的 order by,count 不能刪除,可以通過(guò)以下的方案進(jìn)行優(yōu)化:
涉及count的優(yōu)化
由于count查詢嚴(yán)重影響查詢體驗(yàn),所以可以考慮分情況討論是否需要查詢count。count一般用于前端分頁(yè)展示選擇頁(yè)數(shù),來(lái)進(jìn)行分頁(yè)選擇查詢。count查詢的優(yōu)化方案,將腳本查詢接口的count輸出改為可選輸出,然后通過(guò)入?yún)⒖刂剖欠褫敵?,如果需要輸出再查?code>count,否則不返回count。
a. 對(duì)于頁(yè)面上調(diào)用腳本的查詢接口時(shí),先試探查詢傳入start=5000,limit=5001,首次查詢先通過(guò)入?yún)⒖刂撇徊樵?code>count并且攜帶其他查詢條件,如果返回記錄不為空,則表示滿足條件的記錄大于5000條。
b. 如果能查出一條記錄則表示記錄超過(guò)5000,則后續(xù)的正常分頁(yè)查詢也不查詢count,只將分頁(yè)查詢的返回分頁(yè)數(shù)據(jù)展示到頁(yè)面上,頁(yè)面也不展示count。頁(yè)面也只可以翻頁(yè)到0~5000的記錄,5000以上的無(wú)法看。
c. 如果查不到記錄(表示滿足條件的數(shù)量少于5000)。則可以正常返回count,將返回的count用于前端分頁(yè)的總記錄數(shù)量,此時(shí)返回的分頁(yè)數(shù)據(jù)亦可以正常展示,用法與普通的分頁(yè)查詢用法一致。
多表關(guān)聯(lián)不要使用select * 的方式返回對(duì)應(yīng)字段的記錄
由于多表關(guān)聯(lián)字段的數(shù)量較多,如果是select *,可能會(huì)返回很多不需要的字段記錄,導(dǎo)致增加了非必要的數(shù)據(jù)傳輸。建議不要使用select *,而是根據(jù)需要返回的字段一個(gè)個(gè)列出來(lái),例如只需要id就寫(xiě)為select id。
非必要場(chǎng)景下,避免使用distinct關(guān)鍵字進(jìn)行記錄去重
如果確定了返回的記錄不會(huì)有重復(fù)的,應(yīng)該避免使用distinct關(guān)鍵字進(jìn)行去重,distinct關(guān)鍵字在并發(fā)情況下性能較差。