MySQL查詢性能優化詳情介紹

對于高性能數據庫來說:庫表結構優化、索引優化和查詢優化需要齊頭并進

1.為什么查詢的速度會慢?

查詢其實就是一系列的子任務組成,優化查詢實際上就是:要么消除一些子任務,要么減少子任務執行的次數。

2.慢查詢基礎:優化數據訪問

(1)是否向數據庫請求了不需要的數據

1)查詢了不需要的數據:
比如我們通過select 查詢出了大量的結果,獲取前面的N行之后就關閉結果集,實際上MySQL會查詢出所有的結果集,客戶端接收部分數據后丟棄剩余的數據,這里就存在查詢冗余。所以我們只需要查詢前面的n條記錄就好,利用 ?limit ?關鍵字限制。

2)多表關聯時返回全部的列
我們在進行多表查詢時,經常會碰到
mysql>select * from …….
這樣的查詢其實是非常非常影響性能的,應該用具體的字段名來代替MySQL *

3)總是取出全部的列
禁止寫出 select * ?這樣的語句。

(2)MySQL是否掃描了額外的記錄

在確定了查詢只返回了需要的數據之后(也就是定制查詢的具體字段不要使用通配符 * )

接下來關注的應該是返回結果是否掃描了過多的數據。對于MySQL最簡單的三個指標如下:
(1)響應時間

(2)掃描的行數

(3)返回的行數。

響應時間
響應時間:包括服務時間(真正的查詢時間)和排隊時間(阻塞等待的時間)。

掃描行數和返回的行數
分析查詢時,查看該查詢掃描的行數是非常有幫助的,一定程度上說明該查詢的效率高不高。

掃描的行數和訪問類型
MySQL有好幾種訪問方式可以查找并返回一行結果:全表掃描、索引掃描、范圍掃描、唯一索引查詢、常數引用等。

這里加索引的作用就出來了,索引可以讓MySQL以最高效、掃描行數最少的方式找到記錄。

3.重構查詢的方式

目的就是:找到一個更加優的方法獲得實際需要的結果。

(1)一個復雜查詢還是多個簡單查詢
我們在寫SQL的時候經常需要考慮的一個問題就是:是否需要將一個復雜的查詢分成多個簡單的查詢?

對于MySQL來說,連接和斷開都是非常輕量級的,在返回一個小的查詢結果方面很高效。雖然說盡可能少的查詢當然好,但是在衡量了工作量是否明顯減少之后,將大的查詢分解成小的查詢有時還是很有必要的。

(2)切分查詢
分而治之的思想。有時候我們需要將一個大的查詢切分成片,分部分執行,而且分步之間做一個延時,這樣避免了長時間的鎖住很多的數據。

比如我們在刪除數據時 delete, 如果一次刪除所有需要刪除的數據,可能長時間占用事務,但是我們可以分片,將一個大的delete,通過條件限制,分成多個delete執行,這樣就能提高效率。

(3)分解關聯查詢
很多高性能的應用都會對關聯查詢拆分,比如:

mysql>select?*?from?tag????  left?join?tag_post?on?tag_post.tag_id=tag.id????  left?join?post?on?tag_post.post_id?=?post.idwhere?tag.tag='mysql';

可以分解成

mysql>select?*?from?tag?where?tag='mysql';mysql>select?*?from?tag_post?where?tag_id=1234;  mysql>select?*?from?post?where?post.id?in?(123,345,456,8933);

這么分解的原因是什么呢?
(1)讓MySQL的效率更高;(比如上面查詢的tag已經被緩存了,那么應用就可以跳過第一個查詢了。)

(2)將查詢分解后,執行單個查詢可以減少鎖的競爭。

(3)某些情況下效率也會更高,比如上面的分解后用 in 關鍵字查詢,效率更高。

4.查詢執行的基礎

首先來看看查詢執行的路徑的示意圖:
MySQL查詢性能優化詳情介紹

步驟如下:
(1)客戶端發送一條查詢給服務器;

(2)服務器先檢查查詢緩存,如果命中了緩存,則立刻返回存在緩存中的結果,否則進入下一步。

(3)服務器對SQL進行解析、預處理、再由優化器生成對應的執行計劃。

(4)MySQL會根據優化器生成的執行計劃、調用存儲引擎的MySQL來執行查詢。

(5)將結果返回給客戶端。

(1)MySQL客戶端/服務器通信協議

我們不需要了解通信協議內部是如何實現的,只需理解通信協議是如何工作的。

MySQL的客戶端和服務器通信協議是半雙工的,意味著同一時刻,只能有一方向另一方發送數據。

(2)查詢緩存

在解析一個SQL語句之前,如果緩存是打開的,MySQL會優先檢查這個查詢是否命中查詢緩存中的數據。如果命中了緩存就會直接從緩存中拿到結果集并返回給客戶端。如果沒有命中緩存就會進入下一階段。

(3)查詢優化器

在這一部分最重要的就是查詢優化器了,一條查詢語句可以有很多種執行方式,最后都將返回相同的結果,優化器的作用就是找到最高效的執行計劃。

下面給出MySQL查詢優化器能夠自動處理的優化類型:
?(1)重新定義關聯表的順序:數據表的關聯順序并不總是按照在查詢中指定的順序進行,這個與優化器有關。

(2)將外連接轉換成MySQL

(3)使用等價變換規則:可以減少一些比較或則移除一些恒等的判斷。比如(5=5 and a>5)將被改寫成(a > 5)。

(4)優化 COUNT()、 MIN() 和 MAX() 函數:索引和列是否允許為空可以幫助優化這類表達式:比如求最小值,利用B-Tree結構特點,只需要查詢B-Tree的最左端記錄就OK了。同理對于求max()函數也是一樣。但是對于COUNT(*)這個函數,MyISAM存儲類型維護了一個MySQL來專門存儲表中記錄行的總數。

(5)覆蓋索引掃描:當索引中的列包含所有查詢中需要使用的列時候,MySQL可以直接使用索引返回需要的數據,無需再查詢對應的數據行。

(6)子查詢優化

(8)提前終止查詢:在發現已經滿足查詢需求的時候,MySQL總是能夠立即終止查詢。比如 limit 關鍵字。

(9)列表 IN 的比較代替OR:MySQL會先將IN語句中的數據排序,再通過MySQL來確定列表中的數據是否滿足需求,這是一個O(logn)的復雜度的操作。 如果等價轉換成 OR 就會變成O(n)的時間復雜度。

(4)排序優化

不管怎么說,排序都是一個成本很高的操作,一定要避免對大數據排序。所以我們一定要利用索引列來進行排序,當不能利用索引生成排序結果時候,肯定就會存在回表MySQL的情況,這時候數據量巨大,會使用文件排序。

? 版權聲明
THE END
喜歡就支持一下吧
點贊12 分享