1. 程式人生 > 資料庫 >MySQL優化SQL語句的技巧

MySQL優化SQL語句的技巧

在面對不夠優化、或者效能極差的SQL語句時,我們通常的想法是將重構這個SQL語句,讓其查詢的結果集和原來保持一樣,並且希望SQL效能得以提升。而在重構SQL時,一般都有一定方法技巧可供參考,本文將介紹如何通過這些技巧方法來重構SQL。

一、分解SQL

有時候對於一個複雜SQL,我們首先想到的是是否需要將一個複雜SQL分解成多個簡單SQL,來完成相同業務處理結果。

在以前,大家總是強調需要資料庫層來完成儘可能的工作,這也就不難理解在一些老的產品、專案中時常會看見很多超級複雜、超級長的SQL語句,這樣做的邏輯在以前認為多次互動,在網路頻寬、程式與資料庫間網路通訊等方面是一件代價很高的事情。然後在現在,無論是頻寬還是延遲,網路速度比以前要快的很多,多次互動也沒有太大的問題。即使在一個通用伺服器上,也能夠執行每秒超過10萬的查詢,所以執行多個小查詢現在已經不是大問題了。

複雜SQL的分解,在面對超級複雜SQL語句時,效能提升尤為明顯。所以,在面對超級複雜SQL語句,並且存在效能問題時,推薦分解為小查詢來進行優化

不過,在應用設計的時候,如果一個查詢能夠勝任並且不會產生效能問題,這時完全可以用一個稍微複雜的SQL來完成的,倘若再死板的強制拆分成多個小查詢是不明智的。

在當今很多高效能的應用系統中,都是極力推薦使用單表操作,然後將單表查詢結果在應用程式中進行關聯,以滿足複雜業務的查詢需求。一個SQL可以搞定事情,為何要分開來寫,而且還得在應用程式中多次執行SQL查詢,再進行結果集的關聯,這到底為什麼要這麼做呢?

乍一看,這樣做複雜不說而且沒有什麼好處,原本一條查詢,這樣卻變成了多條查詢。事實上,這樣分解有如下的優勢:

  • 讓快取更高效。在應用程式中,可以很方便地快取單表查詢結果對應的結果物件,便於後續任何時候可以直接從結果物件中獲取資料。
  • 分解查詢後,執行單個查詢可以減少表鎖的競爭。
  • 在程式應用層做關聯,可以更容易對資料庫進行拆分,更容易做到高效能和可擴充套件。
  • 單表查詢效率高於多表複雜查詢。
  • 減少冗餘記錄的查詢。在程式應用層關聯,意味著對於某條記錄應用只需要查詢一次,而在資料庫中做關聯查詢,則可能需要重複地訪問一部分資料記錄。從這點來看,這樣的重構還可能減少網路和記憶體的消耗。

二、查詢切分

有時候對於一個大查詢,即:結果集很大的查詢,我們需要採用“分而治之”的思想,將大查詢切分為小查詢,每個查詢功能完全一樣,只是完成一小部分,每次只返回一小部分查詢結果。通俗來講,就是對where條件的過濾範圍進行切分,每次只查詢其中一部分資料,即:類似於分頁查詢。

這樣做,不管對於SQL查詢本身,還是對於上層業務來說,都是很小的開銷。最典型的的案例就是分頁查詢,目前各類框架都有了很好的支援,如:MyBatis等,只需在實際使用時稍加留意就可避免。

三、執行計劃

使用執行計劃EXPLAIN關鍵字,可以使我們知道MySQL是如何執行SQL語句的,這樣可以幫助我們分析我們的查詢語句或是表結構的效能瓶頸。EXPLAIN的查詢結果還會告訴我們索引主鍵是如何被利用的,資料表是如何被搜尋或排序的…等等。

語法格式是:

EXPLAIN SELECT語句;

通過執行計劃結果,將會指導我們進一步來重構SQL語句,如:增加索引、調整索引順序、避免使用某些函式等等。

關於執行計劃,後續章節將會單獨詳細講解。

四、遵守原則

在平時寫SQL時,養成好的習慣,多加留意,很大程度上就會避免一些SQL效能問題。彙總如下:

  • 永遠為每張表設定一個ID主鍵。
  • 避免使用SELECT *。
  • 為搜尋欄位建立索引。
  • 在Join表的時候使用對應型別的列,並將其索引。
  • 儘可能的使用NOT NULL。
  • 越小的列會越快。
  • 當只要一行資料時使用LIMIT 1。
  • 操作符的優化,儘量不採用不利於索引的操作符,目的就是為了避免全表掃描。

1)in 和not in慎用,儘量用between代替in,用 not exists 代替 not in
2)is null和is not null慎用
3)!=或<>操作符能不用就不用,否則將使引擎放棄使用索引而進行全表掃描。

五、使用查詢快取

當有很多相同的查詢被執行了多次的時候,這些查詢結果會被放入一個快取中,這樣後續的相同查詢就不用操作而直接訪問快取結果了。

MySQL查詢快取儲存查詢返回的完整結果。當查詢命中該快取,MySQL會like返回結果,跳過了解析、優化和執行截斷。

這是提高查詢效能最有效的方法之一,而且這是被MySQL引擎處理的,通常MySQL預設是不開啟查詢快取的,需要手動開啟。

查詢快取對應用程式是完全透明的。應用程式無需關心MySQL是通過查詢返回的還是實際執行返回的結果。事實上,這兩種方式執行的結果是完全相同的。換句話說,查詢快取無需使用任何語法。

隨著現在的通用伺服器越來越強大,查詢快取被發現是一個影響伺服器擴充套件性的因素。它可能成為整個伺服器的資源競爭單點,在多核伺服器上還可能導致伺服器僵死。所以大部分時候應該預設關閉查詢快取,如果查詢快取作用很大的話,可以配置個幾十兆的小快取空間。(在選擇時,需要進行權衡)

關於查詢快取有如下引數可供配置:

  • query_cache_type

是否開啟查詢快取。可以設定OFF、ON、DEMAND,DEMAND表示只有在查詢語句中明確寫入sql_cache的語句才放入查詢快取。

  • query_cache_size

查詢快取使用的總記憶體空間,單位是位元組。這個值必須是1024的整倍數,否則實際分配的資料會和指定的大小有區別。

  • query_cache_min_res_unit

在查詢快取中分配記憶體塊時的最小單位。

  • query_cache_limit

快取的最大查詢結果。如果查詢結果大於這個值,則不會被快取。因為查詢快取在資料生成的時候就開始嘗試快取資料,所以只有當結果全部返回後,MySQL才知道查詢結果是否超出限制。

關於查詢快取,後續章節將會單獨詳細講解。

以上就是MySQL優化SQL語句的技巧的詳細內容,更多關於MySQL優化sql語句的資料請關注我們其它相關文章!