mysql 瓶頸診斷 又快又準的sql瓶頸診斷方法

2021-10-17 18:30:34 字數 4033 閱讀 2348

我們面試經常會被問到資料庫優化這塊,我們很多時候能回答一些大而化之的策略,例如主從分離,分表分庫之類,新增合理的索引,那繼續追問,用的什麼中介軟體主從分離,用的什麼策略進行分表分庫,什麼是合理的索引,加了索引表掃瞄少了多少行,什麼情況下索引會失效,好吧,笑容逐凝固,不知如何作答了,本篇就優先圍繞sql查詢優化本身來聊這個事情;

首先用一張圖來解釋查詢過程:

簡單來說,可以概括成為如下五步:

1.客戶端傳送乙個查詢給伺服器。

2.伺服器先檢查查詢快取,如果命中,則直接返回快取中的結果。如果沒有命中,則進入下一階段(解析器)。

3.伺服器由解析器檢查sql語法是否正確,然後由預處理器檢查sql中的表和字段是否存在,最後由查詢器生成執行計畫。這一步很耗資源。

4.mysql根據優化器生成的執行計畫,呼叫儲存引擎的api來執行查詢。

5.將結果返回給客戶端。

效能浪費在**:

無索引,索引失效導致的慢查詢,這是兩個事情,不要簡單認為新增了索引就萬事大吉;

2.鎖等待;

3.不恰當不符合規範的索引語句;

接下來說剛提到的執行計畫:

執行計畫通常是開發者優化sql語句的第一步。mysql在解析sql語句時,會生成多套執行方案,然後內部會進行乙個成本的計算,然後通過優化器選擇乙個最優的方案執行,然後根據這個方案會生成乙個執行計畫。開發者通過檢視sql語句的執行計畫,可以直觀的了解到mysql是如何解析執行這條sql語句的,然後再針對性的進行優化。

如何檢視sql語句的執行計畫?

語法:explain select語句;

舉例:explain select 1;

explain列的解釋

table

顯示這一行的資料是關於哪張表的

type

這是重要的列,顯示連線使用了何種型別。從最好到最差的連線型別為const、eq_reg、ref、range、indexhe和all

說明:不同連線型別的解釋(按照效率高低的順序排序)

system:表只有一行:system表。這是const連線型別的特殊情況。

const :表中的乙個記錄的最大值能夠匹配這個查詢(索引可以是主鍵或惟一索引)。因為只有一行,這個值實際就是常數,因為mysql先讀這個值然後把它當做常數來對待。

eq_ref:在連線中,mysql在查詢時,從前面的表中,對每乙個記錄的聯合都從表中讀取乙個記錄,它在查詢使用了索引為主鍵或惟一鍵的全部時使用。

ref:這個連線型別只有在查詢使用了不是惟一或主鍵的鍵或者是這些型別的部分(比如,利用最左邊字首)時發生。對於之前的表的每乙個行聯合,全部記錄都將從表中讀出。這個型別嚴重依賴於根據索引匹配的記錄多少—越少越好。

range:這個連線型別使用索引返回乙個範圍中的行,比如使用》或

index:這個連線型別對前面的表中的每乙個記錄聯合進行完全掃瞄(比all更好,因為索引一般小於表資料)。

all:這個連線型別對於前面的每乙個記錄聯合進行完全掃瞄,這一般比較糟糕,應該盡量避免。

possible_keys

顯示可能應用在這張表中的索引。如果為空,沒有可能的索引。可以為相關的域從where語句中選擇乙個合適的語句

key實際使用的索引。如果為null,則沒有使用索引。很少的情況下,mysql會選擇優化不足的索引。這種情況下,可以在select語句中使用use index(indexname)來強制使用乙個索引或者用ignore index(indexname)來強制mysql忽略索引

key_len

使用的索引的長度。在不損失精確性的情況下,長度越短越好

ref顯示索引的哪一列被使用了

rows

mysql認為必須檢查的用來返回請求資料的行數,這一行非常重要

extra

distinct :一旦mysql找到了與行相聯合匹配的行,就不再搜尋了。

not exists :mysql優化了left join,一旦它找到了匹配left join標準的行,就不再搜尋了。

range checked for each record:沒有找到理想的索引,因此對從前面表中來的每乙個行組合,mysql檢查使用哪個索引,並用它來從表中返回行。這是使用索引的最慢的連線之一。

using filesort :看到這個的時候,查詢就需要優化了。mysql需要進行額外的步驟來發現如何對返回的行排序。它根據連線型別以及儲存排序鍵值和匹配條件的全部行的行指標來排序全部行。

using index :列資料是從僅僅使用了索引中的資訊而沒有讀取實際的行動的表返回的,這發生在對錶的全部的請求列都是同乙個索引的部分的時候。

using temporary :看到這個的時候,查詢需要優化了。這裡,mysql需要建立乙個臨時表來儲存結果,這通常發生在對不同的列集進行order by上,而不是group by上。

上面的文字很多,很多概念的東西有點難以讀懂,接下來我們舉一些實際的例子來說明概念;

新建一張簡單的表,塞10000條左右的資料,表結構如下:

順帶貼一下我的造數過程,資料量自動改變i的值即可:

begin

declare i int;

set i=3000;

while i<10000 do

insert into user  values (i,concat('cctester',i),'123456',concat('cc',i));

set i=i+1;

end while;

end先做乙個簡單的對比,在name上面新增了索引,而description未新增:

我們可以看到時間的差異,在一萬條基礎資料的情況下,未新增索引的時間多了20倍,那我們繼續分析,這多出來的20倍時間在做什麼呢?

我們看執行計畫的對比分析:

我們通過對比可以看出第二條sql的rows遍歷了9984行,做了一次全表掃瞄,而新增索引的做了一次常量查詢,取了一行;

這麼說是不是比較清晰,相對直觀的了解到時間消耗點,那我們仔細看一下執行計畫,為什麼我說的那個未新增索引的extra列顯示了using index呢,這是我之前留的乙個破綻,接下來我們引出另外乙個概念多列索引的最左字首規則;

多列索引通俗來講就是乙個索引可以定義在表的多個列上,為什麼使用多列索引呢?

以多列索引(a,b,c)為例

建立這樣的索引相當於建立了索引a、ab、abc三個索引。乙個索引頂三個索引當然是好事,畢竟每多乙個索引,都會增加寫操作的開銷和磁碟空間的開銷。

同樣的有聯合索引(a,b,c),如果有如下的sql: select a,b,c from table where a=*** and b = ***。那麼mysql可以直接通過遍歷索引取得資料,而無需讀表,這減少了很多的隨機io操作。減少io操作,特別的隨機io其實是dba主要的優化策略。所以,在真正的實際應用中,覆蓋索引是主要的提公升效能的優化手段之一

通過索引篩選出的資料越少。有1000w條資料的表,有如下sql:select * from table where a = 1 and b =2 and c = 3,假設每個條件可以篩選出10%的資料,如果只有單值索引,那麼通過該索引能篩選出1000w*10%=100w 條資料,然後再回表從100w條資料中找到符合b=2 and c= 3的資料,然後再排序,再分頁;如果是復合索引,通過索引篩選出1000w *10% *10% *10%=1w,然後再排序、分頁,哪個更高效,很容易辨別出來;

那最左字首又是啥意思呢,還是用通俗的解釋就是必須用到索引的第乙個字段。

多列索引(a,b,c)查詢組合可以使a,ab,abc,ac,但直接使用bc,b,c就會失效;

回到上面的例子,我在name,password,description上建立了聯合索引,但直接使用deccrption列並沒有回行資料,並不符合最左字首的規則,所以等於索引沒有使用;

mysql的瓶頸 如何衡量mySQL的瓶頸?

如果您的操作遇到cpu限制問題,那麼您肯定需要檢視 a 資料庫的結構 是否完全標準化。糟糕的資料庫結構會導致複雜的查詢進入處理器。b 您的索引 您的查詢所需的一切都已充分索引。缺乏索引可能會嚴重影響處理器和記憶體。要檢查索引,請執行 explain your query 在結果說明中沒有使用索引的任...

mysql內診 筆記 mysql優化前的診斷

不能盲目的做優化,要先找準問題所在,是cpu,記憶體,io?還是峰值,語句?一 mysql優化套路 二 相關命令 觀察伺服器狀態 mysql show status 或 mysqladmin exts 觀察連線的工作狀態 mysql show processlist 狀態說明 converting ...

mysql資料庫健康診斷 MySQL 慢的診斷思路

1 問題 如果遇到 mysql 慢的話,你的第一印象是什麼,mysql 資料庫如果效能不行,又該是如何處理的?一些反饋如下 第一反應是再試一次 第二個反應是優化一下 sql 第三個反應是調大 buffer pool,然後開始換硬體了,換一下 ssd 分析一下這些現象背後隱藏的意義 如果再試一次能夠成...