五個提升SQL語句性能的小竅門,進一步提升查詢性能
在進行數(shù)據(jù)庫操作時,優(yōu)化SQL語句是提升性能和效率的關(guān)鍵步驟之一。無論是處理大規(guī)模數(shù)據(jù)還是簡單的查詢,優(yōu)化SQL語句都可以明顯改善系統(tǒng)的響應(yīng)時間和資源利用率。
本文介紹五個實用的優(yōu)化SQL的技巧,幫助讀者更好地利用索引、避免性能瓶頸,并提高數(shù)據(jù)庫的整體性能。
1 內(nèi)連接說明
當涉及到多個表的連接查詢時,通常使用join關(guān)鍵字。
最常用的連接方式是左連接和內(nèi)連接。
- left join:找到兩個表的交集,并包含左表中剩余的數(shù)據(jù)。
- inner join:找到兩個表的交集數(shù)據(jù)。
以下是使用inner join的示例:
select o.id,o.code,u.name
from order o
inner join user u on o.user_id = u.id
where u.status=1;
如果兩個表使用inner join關(guān)聯(lián),MySQL會自動選擇兩個表中的小表驅(qū)動大表,因此在性能上不會出現(xiàn)太多問題。
以下是使用left join的示例:
select o.id,o.code,u.name
from order o
left join user u on o.user_id = u.id
where u.status=1;
如果兩個表使用left join關(guān)聯(lián),MySQL默認使用左連接關(guān)鍵字驅(qū)動右側(cè)的表。如果左表中存在大量數(shù)據(jù),則可能會出現(xiàn)性能問題。
需要注意的是,在使用left join查詢時,應(yīng)該將小表放在左側(cè),將大表放在右側(cè)。如果可以使用inner join,應(yīng)盡量避免使用left join。
2 限制索引的數(shù)量
眾所周知,索引可以大幅提高SQL查詢的性能,但索引的數(shù)量并不是越多越好。
因為當向表中添加新數(shù)據(jù)時,同時需要為其創(chuàng)建索引,而索引需要額外的存儲空間和一定的性能消耗。
單個表中的索引數(shù)量應(yīng)盡量控制在5個以內(nèi),單個索引中的字段數(shù)量也不應(yīng)超過5個。
MySQL使用的B+樹結(jié)構(gòu)來保存索引,B+樹索引在插入、更新和刪除操作時需要進行更新。如果索引過多,將消耗大量的額外性能。
那么,如果表中的索引過多,超過了5個怎么辦呢?
這個問題需要辯證地看待。如果你的系統(tǒng)并發(fā)性較低,表中的數(shù)據(jù)量也不是很大,實際上可以使用超過5個的索引,只要不過度即可。
但對于一些高并發(fā)的系統(tǒng),務(wù)必遵守單個表上不超過5個索引的限制。
那么,高并發(fā)系統(tǒng)如何優(yōu)化索引的數(shù)量呢?
如果可以建立聯(lián)合索引,就不要建立單個索引,可以刪除一些無用的單個索引。
將一些查詢功能遷移到其他類型的數(shù)據(jù)庫中,比如Elastic Seach、HBase等,只需在業(yè)務(wù)表中建立少量的關(guān)鍵索引即可。
3 選擇適當?shù)淖侄晤愋?/h3>
char表示固定長度的字符串類型,該類型的字段存儲空間是固定的,會浪費存儲空間。
alter table order
add column code char(20) NOT NULL;
varchar表示可變長度的字符串類型,該類型的字段存儲空間會根據(jù)實際數(shù)據(jù)的長度進行調(diào)整,不會浪費存儲空間。
alter table order
add column code varchar(20) NOT NULL;
如果是固定長度的字段,比如用戶的手機號碼,一般是11位,可以定義為長度為11字節(jié)的char類型。
但如果是企業(yè)名稱字段,如果定義為char類型,會存在問題。
如果長度定義得過長,例如定義為200字節(jié),而實際企業(yè)名稱只有50字節(jié),將浪費150字節(jié)的存儲空間。
如果長度定義得過短,例如定義為50字節(jié),而實際企業(yè)名稱有100字節(jié),將無法存儲,并拋出異常。
因此,建議將企業(yè)名稱改為varchar類型。可變長度字段的存儲空間較小,可以節(jié)省存儲空間,對于查詢來說,在相對較小的字段中搜索效率顯然更高。
選擇字段類型時,應(yīng)遵循以下原則:
如果可以使用數(shù)字類型,就不要使用字符串,因為數(shù)字類型的存儲空間更小,查詢效率更高。
盡量使用小型類型,例如使用bit類型存儲布爾值,tinyint類型存儲枚舉值等。
對于固定長度的字段,可以使用char類型。
對于可變長度的字段,可以使用varchar類型。
對于金額字段,使用decimal類型,避免精度丟失的問題。
4 提高group by的效率
在許多業(yè)務(wù)場景中,需要使用group by關(guān)鍵字。它的主要功能是進行去重和分組。
通常,與having一起使用,表示按照某些條件進行分組,然后再過濾數(shù)據(jù)。
錯誤示例
select user_id,user_name from order
group by user_id
having user_id <= 200;
這種寫法性能較差。它首先根據(jù)用戶ID對所有訂單進行分組,然后篩選出用戶ID大于或等于200的用戶。
分組是一個相對耗時的操作,為什么不在分組之前縮小數(shù)據(jù)范圍呢?
正確示例
select user_id,user_name from order
where user_id <= 200
group by user_id
使用where條件在分組之前過濾掉冗余數(shù)據(jù),這樣在分組時效率會更高。
實際上,這是一個思路,不僅僅適用于group by的優(yōu)化。在SQL語句執(zhí)行一些耗時操作之前,應(yīng)盡量縮小數(shù)據(jù)范圍,這樣可以提高整體SQL的性能。
5 索引優(yōu)化
在SQL優(yōu)化中,索引優(yōu)化是非常重要的內(nèi)容。
在許多情況下,使用索引和不使用索引時,SQL語句的執(zhí)行效率會有很大差異。因此,索引優(yōu)化是SQL優(yōu)化的首選。
索引優(yōu)化的第一步是檢查SQL語句是否已經(jīng)使用了索引。
那么,如何檢查SQL是否使用了索引呢?
可以使用explain命令查看MySQL的執(zhí)行計劃。
explain select * from `order` where code='002';
圖片
以下是索引失效的一些常見原因:
- 不滿足最左前綴原則。
- 范圍索引列沒有放在最后。
- 使用了select *。
- 對索引列進行了計算。
- 對索引列使用了函數(shù)。
- 字符串類型沒有加引號。
- 使用了like %。
- 錯誤地使用了is null。
- 錯誤地使用了or。
如果不是由于上述原因,就需要進一步調(diào)查其他原因。
此外,您是否曾經(jīng)遇到過這樣的情況:明明是相同的SQL,只是輸入?yún)?shù)不同。有時候索引a生效,有時候索引b生效?
有時候MySQL會選擇錯誤的索引。
如果有必要,可以使用force index來強制查詢SQL使用特定的索引。