SQL優化的這15招,真香!
當前位置:點晴教程→知識管理交流
→『 技術文檔交流 』
前言sql優化是一個大家都比較關注的熱門話題,無論你在面試,還是工作中,都很有可能會遇到。 如果某天你負責的某個線上接口,出現了性能問題,需要做優化。那么你首先想到的很有可能是優化sql語句,因為它的改造成本相對于代碼來說也要小得多。 那么,如何優化sql語句呢? 這篇文章從15個方面,分享了sql優化的一些小技巧,希望對你有所幫助。 (我最近開源了一個基于 SpringBoot+Vue+uniapp 的商城項目,歡迎訪問和star。)[https://gitee.com/dvsusan/susan_mall] 1 避免使用select *很多時候,我們寫sql語句時,為了方便,喜歡直接使用 反例:
在實際業務場景中,可能我們真正需要使用的只有其中一兩列。查了很多數據,但是不用,白白浪費了數據庫資源,比如:內存或者cpu。 此外,多查出來的數據,通過網絡IO傳輸的過程中,也會增加數據傳輸的時間。 還有一個最重要的問題是: 那么,如何優化呢? 正例:
sql語句查詢時,只查需要用到的列,多余的列根本無需查出來。 2 用union all代替union我們都知道sql語句使用 而如果使用 反例:
排重的過程需要遍歷、排序和比較,它更耗時,更消耗cpu資源。 所以如果能用union all的時候,盡量不用union。 正例:
除非是有些特殊的場景,比如union all之后,結果集中出現了重復數據,而業務場景中是不允許產生重復數據的,這時可以使用union。 3 小表驅動大表小表驅動大表,也就是說用小表的數據集驅動大表的數據集。 假如有order和user兩張表,其中order表有10000條數據,而user表有100條數據。 這時如果想查一下,所有有效的用戶下過的訂單列表。 可以使用
也可以使用
前面提到的這種業務場景,使用in關鍵字去實現業務需求,更加合適。 為什么呢? 因為如果sql語句中包含了in關鍵字,則它會優先執行in里面的 而如果sql語句中包含了exists關鍵字,它優先執行exists左邊的語句(即主查詢語句)。然后把它作為條件,去跟右邊的語句匹配。如果匹配上,則可以查詢出數據。如果匹配不上,數據就被過濾掉了。 這個需求中,order表有10000條數據,而user表有100條數據。order表是大表,user表是小表。如果order表在左邊,則用in關鍵字性能更好。 總結一下:
不管是用in,還是exists關鍵字,其核心思想都是用小表驅動大表。 4 批量操作如果你有一批數據經過業務處理之后,需要插入數據,該怎么辦? 反例:
在循環中逐條插入數據。
該操作需要多次請求數據庫,才能完成這批數據的插入。 但眾所周知,我們在代碼中,每次遠程請求數據庫,是會消耗一定性能的。而如果我們的代碼需要請求多次數據庫,才能完成本次業務功能,勢必會消耗更多的性能。 那么如何優化呢? 正例:
提供一個批量插入數據的方法。
這樣只需要遠程請求一次數據庫,sql性能會得到提升,數據量越多,提升越大。 但需要注意的是,不建議一次批量操作太多的數據,如果數據太多數據庫響應也會很慢。批量操作需要把握一個度,建議每批數據盡量控制在500以內。如果數據多于500,則分多批次處理。 5 多用limit有時候,我們需要查詢某些數據中的第一條,比如:查詢某個用戶下的第一個訂單,想看看他第一次的首單時間。 反例:
根據用戶id查詢訂單,按下單時間排序,先查出該用戶所有的訂單數據,得到一個訂單集合。 然后在代碼中,獲取第一個元素的數據,即首單的數據,就能獲取首單時間。
雖說這種做法在功能上沒有問題,但它的效率非常不高,需要先查詢出所有的數據,有點浪費資源。 那么,如何優化呢? 正例:
使用
例如:
這樣即使誤操作,比如把id搞錯了,也不會對太多的數據造成影響。 6 in中值太多對于批量查詢接口,我們通常會使用 sql語句如下:
如果我們不做任何限制,該查詢語句一次性可能會查詢出非常多的數據,很容易導致接口超時。 這時該怎么辦呢?
可以在sql中對數據用limit做限制。 不過我們更多的是要在業務代碼中加限制,偽代碼如下:
還有一個方案就是:如果ids超過500條記錄,可以分批用多線程去查詢數據。每批只查500條記錄,最后把查詢到的數據匯總到一起返回。 不過這只是一個臨時方案,不適合于ids實在太多的場景。因為ids太多,即使能快速查出數據,但如果返回的數據量太大了,網絡傳輸也是非常消耗性能的,接口性能始終好不到哪里去。 7 增量查詢有時候,我們需要通過遠程接口查詢數據,然后同步到另外一個數據庫。 反例:
如果直接獲取所有的數據,然后同步過去。這樣雖說非常方便,但是帶來了一個非常大的問題,就是如果數據很多的話,查詢性能會非常差。 這時該怎么辦呢? 正例:
按id和時間升序,每次只同步一批數據,這一批數據只有100條記錄。每次同步完成之后,保存這100條數據中最大的id和時間,給同步下一批數據的時候用。 通過這種增量查詢的方式,能夠提升單次查詢的效率。 8 高效的分頁有時候,列表頁在查詢數據時,為了避免一次性返回過多的數據影響接口性能,我們一般會對查詢接口做分頁處理。 在mysql中分頁一般用的
如果表中數據量少,用limit關鍵字做分頁,沒啥問題。但如果表中數據量很多,用它就會出現性能問題。 比如現在分頁參數變成了:
mysql會查到1000020條數據,然后丟棄前面的1000000條,只查后面的20條數據,這個是非常浪費資源的。 那么,這種海量數據該怎么分頁呢? 優化sql:
先找到上次分頁最大的id,然后利用id上的索引查詢。不過該方案,要求id是連續的,并且有序的。 還能使用
需要注意的是between要在唯一索引上分頁,不然會出現每頁大小不一致的問題。 9 用連接查詢代替子查詢mysql中如果需要從兩張以上的表中查詢出數據的話,一般有兩種實現方式: 子查詢的例子如下:
子查詢語句可以通過 子查詢語句的優點是簡單,結構化,如果涉及的表數量不多的話。 但缺點是mysql執行子查詢時,需要創建臨時表,查詢完畢后,需要再刪除這些臨時表,有一些額外的性能消耗。 這時可以改成連接查詢。 具體例子如下:
10 join的表不宜過多根據阿里巴巴開發者手冊的規定,join表的數量不應該超過 反例:
如果join太多,mysql在選擇索引的時候會非常復雜,很容易選錯索引。 并且如果沒有命中中,nested loop join 就是分別從兩個表讀一行數據進行兩兩對比,復雜度是 n^2。 所以我們應該盡量控制join表的數量。 正例:
如果實現業務場景中需要查詢出另外幾張表中的數據,可以在a、b、c表中 不過我之前也見過有些ERP系統,并發量不大,但業務比較復雜,需要join十幾張表才能查詢出數據。 所以join表的數量要根據系統的實際情況決定,不能一概而論,盡量越少越好。 11 join時要注意我們在涉及到多張表聯合查詢的時候,一般會使用 而join使用最多的是left join和inner join。
使用inner join的示例如下:
如果兩張表使用inner join關聯,mysql會自動選擇兩張表中的小表,去驅動大表,所以性能上不會有太大的問題。 使用left join的示例如下:
如果兩張表使用left join關聯,mysql會默認用left join關鍵字左邊的表,去驅動它右邊的表。如果左邊的表數據很多時,就會出現性能問題。
12 控制索引的數量眾所周知,索引能夠顯著的提升查詢sql的性能,但索引數量并非越多越好。 因為表中新增數據時,需要同時為它創建索引,而索引是需要額外的存儲空間的,而且還會有一定的性能消耗。 阿里巴巴的開發者手冊中規定,單表的索引數量應該盡量控制在 mysql使用的B+樹的結構來保存索引的,在insert、update和delete操作時,需要更新B+樹索引。如果索引過多,會消耗很多額外的性能。 那么,問題來了,如果表中的索引太多,超過了5個該怎么辦? 這個問題要辯證的看,如果你的系統并發量不高,表中的數據量也不多,其實超過5個也可以,只要不要超過太多就行。 但對于一些高并發的系統,請務必遵守單表索引數量不要超過5的限制。 那么,高并發系統如何優化索引數量? 能夠建聯合索引,就別建單個索引,可以刪除無用的單個索引。 將部分查詢功能遷移到其他類型的數據庫中,比如:Elastic Seach、HBase等,在業務表中只需要建幾個關鍵索引即可。 13 選擇合理的字段類型
如果是長度固定的字段,比如用戶手機號,一般都是11位的,可以定義成char類型,長度是11字節。 但如果是企業名稱字段,假如定義成char類型,就有問題了。 如果長度定義得太長,比如定義成了200字節,而實際企業長度只有50字節,則會浪費150字節的存儲空間。 如果長度定義得太短,比如定義成了50字節,但實際企業名稱有100字節,就會存儲不下,而拋出異常。 所以建議將企業名稱改成varchar類型,變長字段存儲空間小,可以節省存儲空間,而且對于查詢來說,在一個相對較小的字段內搜索效率顯然要高些。 我們在選擇字段類型時,應該遵循這樣的原則:
還有很多原則,這里就不一一列舉了。 14 提升group by的效率我們有很多業務場景需要使用 通常它會跟 反例:
這種寫法性能不好,它先把所有的訂單根據用戶id分組之后,再去過濾用戶id大于等于200的用戶。 分組是一個相對耗時的操作,為什么我們不先縮小數據的范圍之后,再分組呢? 正例:
使用where條件在分組前,就把多余的數據過濾掉了,這樣分組時效率就會更高一些。
15 索引優化sql優化當中,有一個非常重要的內容就是: 很多時候sql語句,走了索引,和沒有走索引,執行效率差別很大。所以索引優化被作為sql優化的首選。 索引優化的第一步是:檢查sql語句有沒有走索引。 那么,如何查看sql走了索引沒? 可以使用 例如:
結果: 說實話,sql語句沒有走索引,排除沒有建索引之外,最大的可能性是索引失效了。 下面說說索引失效的常見原因: 此外,你有沒有遇到過這樣一種情況:明明是同一條sql,只有入參不同而已。有的時候走的索引a,有的時候卻走的索引b? 沒錯,有時候mysql會選錯索引。 必要時可以使用 轉自?https://www.cnblogs.com/12lisu/p/18654428 該文章在 2025/1/7 15:39:06 編輯過 |
關鍵字查詢
相關文章
正在查詢... |