mysql查詢效能優化

2021-08-11 06:50:44 字數 4516 閱讀 3877

mysql執行查詢的過程

如圖:

1)客戶端首先通過客戶端/伺服器通訊協議與mysql伺服器建立起連線

2)客戶端傳送一條sql語句

判斷是否為查詢語句,如果是查詢語句,則先在查詢快取區雜湊查詢對應sql的資料,如果未找到,則需要呼叫解析器解析、預處理、再由優化器生成對應的查詢執行計畫

3)mysql根據優化器生成的執行計畫,呼叫儲存引擎的api執行查詢

4)將查詢到的結果快取到查詢快取中,在從查詢快取中返回資料給優化器

基礎模組詳解:

1)mysql客戶端/伺服器通訊協議

半雙工通訊協議,即在任何乙個時刻,要麼由伺服器向客戶端傳送資料,要麼由客戶端向伺服器傳送資料,這兩個動作不能同時發生。

優點:簡單快速

缺點:一旦一端開始傳送訊息,另一端要接受完完整訊息才能響應它

客戶端不斷地從伺服器接收資料,客戶端沒辦法讓伺服器停下來,可以通過加limit限制條件

2)查詢快取

mysql查詢將獲得全部結果集並快取到記憶體中。

目的:mysql通常需要等待所有的資料都已經傳送給了客戶端才能釋放這條查詢所占用的資源,接受結果並將其放到快取中可以較少伺服器的壓力,讓查詢早點結束釋放資源

3)查詢優化處理

查詢優化處理包括解析sql、預處理、優化sql執行計畫,產生語法錯誤將終止查詢

sql解析:通過關鍵字將sql語句進行解析,生成一棵對應的「解析樹」。解析過程中解析器會使用mysql語法規則驗證。

預處理器:進一步檢查解析樹是否合法,如資料表和資料列書否存在,解析名字和別名是否有歧義。驗證許可權

查詢優化器:將sql轉化為執行計畫,並找到最好的執行計畫(一條查詢可以有多種執行方式,最終都返回相同結果),基於成本選擇最好(即成本最小)的執行計畫

導致mysql優化器選擇錯誤的執行計畫的幾種情況:

①:統計資訊不準確。mysql依賴儲存引擎提供的統計資訊來評估成本。innodb因為其mvcc架構,不能維護乙個資料表的行數的精確統計資訊

②:執行計畫中的成本估算不等於實際執行的成本,因為優化器在評估成本的時候不考慮任何層面的快取,都是假設需要讀取一次磁碟i/o,所以如果有些資料被還快取在記憶體中其訪問成本更低,但是統計資訊無法知道這一點

③:mysql最優可能並不是查詢時間最短的,因為其是基於成本模型選擇執行計畫的

④:不考慮併發查詢

⑥:並不是任何時候都基於成本的優化,有時候基於一些固定的規則,比如如果有全文索引,則會使用全文索引

⑦:不考慮不受其控制的操作的成本,例如執行儲存過程或使用者自定義函式

mysql通過優化策略生成乙個最優的執行計畫,優化策略可以分為靜態優化和動態優化

靜態優化:編譯時優化,在第一次完成以後一直有效。靜態優化可以直接對解析樹進行分析,然後完成優化

動態優化:執行時優化,在每次查詢時都需要重新評估

mysql能夠處理的優化:

①重新定義關聯表的順序。並不是按照在sql中指定的順序進行的,由優化器決定關聯的順序

②將外連線轉化為內連線。並不是所有的out join語句都是以外連線的方式進行的where條件、庫表結構可能會讓外連線變為內連線。

③使用等價變換規則。移除恆成立和橫不成立的判斷,並通過簡單變換來簡化並規範表示式(個人覺得這個步驟在寫sql語句的時候就應該盡量避免)

④優化count()、min()、max()。

⑤預估並轉化為常數表示式。如在索引上使用min()函式,在主鍵上或者唯一鍵查詢語句會轉化為常數表示式

⑥覆蓋索引掃瞄

⑦子查詢優化

⑧提前終止查詢。如limit,或發現不成立的條件

⑨等值傳播

⑩列表in()的比較。在mysql中in()不等同於or()條件,mysql將in()列表中的資料先進行排序,然後通過二分查詢的方式來確定列表的值是否滿足條件,對於in()列表中有大量取值的時候,處理速度將更快。or()的查詢複雜度為o(n),in()的查詢複雜度為o(log n)

快取優化器的效能:

如果使用查詢快取,在進行讀寫操作時會帶來額外的資源消耗,消耗主要體現在以下幾個方面

1)查詢的時候會檢查是否命中快取,這個消耗相對較小

2)如果沒有命中查詢快取,mysql會判斷該查詢是否可以被快取,而且系統中還沒有對應的快取,則會將其結果寫入查詢快取

3)如果乙個表被更改了,那麼使用那個表的所有緩衝查詢將不再有效,並且從緩衝區中移出。這包括那些對映到改變了的表的使用merge表的查詢。乙個表可以被許多態別的語句更改,例如insert、update、delete、truncate、alter table、drop table或drop database。

對於innodb而言,事物的一些特性還會限制查詢快取的使用。當在事物a中修改了b表時,因為在事物提交之前,對b表的修改對其他的事物而言是不可見的。為了保證快取結果的正確性,innodb採取的措施讓所有涉及到該b表的查詢在事物a提交之前是不可快取的。如果a事物長時間執行,會嚴重影響查詢快取的命中率

查詢快取的空間不要設定的太大。

因為查詢快取是靠乙個全域性鎖操作保護的,如果查詢快取配置的記憶體比較大且裡面存放了大量的查詢結果,當查詢快取失效的時候,會長時間的持有這個全域性鎖。因為查詢快取的命中檢測操作以及快取失效檢測也都依賴這個全域性鎖,所以可能會導致系統僵死的情況。(那可以將查詢快取空間設定為0,在應用層交給redis進行處理?或者在應用程式中並不會出現這些效能不佳的問題?)

查詢優化的實質

優化查詢就是遵循一些原則讓優化器能夠按照預想的合理的方式執行

為什麼會出現慢查詢

1.向資料庫請求了不需要的資料(請求超過實際需要的資料,然後這些多餘的資料被應用程式丟棄)

常見案列:

1)使用select *。取出全部列,會讓優化器無法使用覆蓋索引進行優化,消耗更多的記憶體資源、cpu、i/o。但是對於快取,查詢出所有的列是乙個好的操作。並且也有人認為,這種有點浪費資料庫資源的方式可以簡化開發,因為能夠提高**片段的復用性。

2)重複查詢相同的資料,即反覆呼叫相同的sql語句。對於同步呼叫相同的資料可以使用快取。

衡量查詢開銷的指標

1)響應的時間 = 服務時間+排隊時間

服務時間是指資料庫處理這個查詢正真執行的時間,排隊時間是指伺服器因為等待某些資源而沒有正真執行的時間,如等待鎖釋放或等待i/o操作

2)掃瞄的行數

一般是可以用來衡量查詢的效率,掃瞄的行數越多,其查詢效率就越低。因為如果掃瞄的是很短的行或者是記憶體中的資料,即使掃瞄很多的行,其查詢效率相對來說還是挺高的

3)返回的行數

這三個指標將被記錄在慢查詢日誌中

mysql如何應用where

where是用來過濾不匹配的條件,刪選掉不需要的資料,mysql會在不同的層次使用where條件進行過濾。效能由好到壞

1)在索引中使用where過濾不匹配的機率。在儲存引擎中完成

2)使用覆蓋掃瞄(extra:using index)來返回記錄,直接從索引中過濾返回滿足條件的資料。在mysql服務層中完成。無需回表

3)在資料表中返回資料(extr:using where)在mysql服務層中完成。mysql需要先從資料表中讀出記錄然後過濾。

優化需要掃瞄大量行但只返回少數行的sql語句

1)建立覆蓋索引

2)改變庫表結構,如使用單獨的彙總表

3)重寫查詢語句

如何重構查詢

1)切分查詢,將乙個大查詢分為多個小查詢,每個查詢功能完全一樣,只完成一部分,每次只完成一部分查詢結果

例子:一次性刪除多條資料

如果一次性刪除很多資料,則可能一次性需要鎖住很多資料,佔滿整個事務日誌,耗盡系統資源,阻塞很多小但很重要的查詢。需要將乙份delete語句切分成多個較小的查詢,盡可能小的影響mysql效能,比如如下sql語句:

delete from message where create < date_sub(now(),interval 3 month);
2)分解關聯查詢

將關聯查詢進行分解,轉化為對每乙個表進行一次單錶查詢,然後將結果在應用程式中進行關聯

分解關聯查詢的優勢:

1)讓快取的效率更高。許多應用程式可以方便的快取單錶查詢對應的結果物件

2)相當於在應用中實現了雜湊關聯,而不是使用mysql的巢狀迴圈關聯

3)執行單個查詢可以減少鎖的競爭

4)在應用層做關聯,更容易對資料庫進行拆分,更容易做到高效能和可擴充套件性

5)查詢本身效率將提公升

6)減少冗餘記錄的查詢

應用場景:

1)應用能夠方便的快取單個查詢的結果

2)當可以將資料分布到不同的mysql服務上時

3)能夠使用in()方式代替關聯查詢時

mysql查詢效能優化 MySQL 查詢效能優化

在日常開發中,程式設計師寫的最多的除了bug之外,應該算是sql語句了。sql的質量影響了程式的響應速度,只有利用mysql的特性,才能讓mysql更有效的執行查詢sql,充分發揮mysql的優勢,並避開它的弱點。為什麼查詢速度會慢?在編寫sql之前,需要清楚一點 真正重要的是響應時間。如果我們把查...

mysql 查詢效能優化

mysql 執行查詢,客戶端向 mysql 傳送請求的時候,mysql 伺服器執行一系列過程,保證查詢語句在 mysql 中得到最高效能的效率。客戶端傳送一條查詢給伺服器 2 伺服器先檢查查詢快取,如果命中了快取,則返回儲存在快取中的結果。否則,進入下乙個階段。3 伺服器進行 sql解析 預處理,再...

MySql查詢效能優化

在訪問資料庫時,應該只請求需要的行和列。請求多餘的行和列會消耗mysql伺服器的cpu和記憶體資源,並增加網路開銷。例如在處理分頁時,應該使用limit限制mysql只返回一頁的資料,而不是向應用程式返回全部資料後,再由應用程式過濾不需要的行。當一行資料被多次使用時可以考慮將資料行快取起來,避免每次...