MySQL查詢優化

2022-08-30 22:06:29 字數 2804 閱讀 5499

首先看兩幅圖,mysql的邏輯架構和查詢過程

客戶端/服務端通訊協議:

mysql客戶端/服務端通訊協議是「半雙工」的:在任一時刻,要麼是伺服器向客戶端傳送資料,要麼是客戶端向伺服器傳送資料,這兩個動作不能同時發生。一旦一端開始傳送訊息,另一端要接收完整個訊息才能響應它,所以我們無法也無須將乙個訊息切成小塊獨立傳送,也沒有辦法進行流量控制。

客戶端用乙個單獨的資料報將查詢請求傳送給伺服器,所以當查詢語句很長的時候,需要設定max_allowed_packet引數。但是需要注意的是,如果查詢實在是太大,服務端會拒絕接收更多資料並丟擲異常。

與之相反的是,伺服器響應給使用者的資料通常會很多,由多個資料報組成。但是當伺服器響應客戶端請求時,客戶端必須完整的接收整個返回結果,而不能簡單的只取前面幾條結果,然後讓伺服器停止傳送。因而在實際開發中,盡量保持查詢簡單且只返回必需的資料,減小通訊間資料報的大小和數量是乙個非常好的習慣,這也是查詢中盡量避免使用select *以及加上limit限制的原因之一。

查詢快取:

在解析乙個查詢語句前,如果查詢快取是開啟的,那麼mysql會檢查這個查詢語句是否命中查詢快取中的資料。如果當前查詢恰好命中查詢快取,在檢查一次使用者許可權後直接返回快取中的結果。這種情況下,查詢不會被解析,也不會生成執行計畫,更不會執行。

mysql將快取存放在乙個引用表(非 table,可以認為是類似於hashmap的資料結構),通過乙個雜湊值索引,這個雜湊值通過查詢本身、當前要查詢的資料庫、客戶端協議版本號等一些可能影響結果的資訊計算得來。所以兩個查詢在任何字元上的不同(例如:空格、注釋),都會導致快取不會命中。

如果查詢中包含任何使用者自定義函式、儲存函式、使用者變數、臨時表、mysql庫中的系統表,其查詢結果都不會被快取。比如函式now()或者current_date()會因為不同的查詢時間,返回不同的查詢結果,再比如包含current_user或者connecion_id()的查詢語句會因為不同的使用者而返回不同的結果,將這樣的查詢結果快取起來沒有任何的意義。

既然是快取,就會失效,那查詢快取何時失效呢?mysql的查詢快取系統會跟蹤查詢中涉及的每個表,如果這些表(資料或結構)發生變化,那麼和這張表相關的所有快取資料都將失效。所以在任何的寫操作時,mysql必須將對應表的所有快取都設定為失效。如果查詢快取非常大或者碎片很多,這個操作就可能帶來很大的系統消耗,甚至導致系統僵死一會兒。而且查詢快取對系統的額外消耗也不僅僅在寫操作,讀操作也不例外:

任何的查詢語句在開始之前都必須經過檢查,即使這條sql語句永遠不會命中快取

如果查詢結果可以被快取,那麼執行完成後,會將結果存入快取,也會帶來額外的系統消耗

所以並不是什麼情況下查詢快取都會提高系統效能,快取和失效都會帶來額外消耗,只有當快取帶來的資源節約大於其本身消耗的資源時,才會給系統帶來效能提公升。

語法解析和預處理:

mysql通過關鍵字將sql語句進行解析,並生成一顆對應的解析樹。這個過程解析器主要通過語法規則來驗證和解析。比如sql中是否使用了錯誤的關鍵字或者關鍵字的順序是否正確等等。預處理則會根據mysql規則進一步檢查解析樹是否合法。比如檢查要查詢的資料表和資料列是否存在等。

查詢優化:

經過一系列操作步驟生成的語法樹被認為是合法的了,並且由優化器將其轉化成查詢計畫。多數情況下,一條查詢可以有很多種執行方式,最後都返回相應的結果。優化器的作用就是找到這其中最好的執行計畫。

mysql使用基於成本的優化器,它嘗試**乙個查詢使用某種執行計畫時的成本,並選擇其中成本最小的乙個。在mysql可以通過查詢當前會話的last_query_cost的值來得到其計算當前查詢的成本。

有非常多的原因會導致mysql選擇錯誤的執行計畫,比如統計資訊不準確、不會考慮不受其控制的操作成本(使用者自定義函式、儲存過程)、mysql認為的最優跟我們想的不一樣(我們希望執行時間盡可能短,但mysql值選擇它認為成本小的,但成本小並不意味著執行時間短)等等。

mysql的查詢優化器是乙個非常複雜的部件,它使用了非常多的優化策略來生成乙個最優的執行計畫:

查詢執行引擎:

在完成解析和優化階段以後,mysql會生成對應的執行計畫,查詢執行引擎根據執行計畫給出的指令逐步執行得出結果。整個執行過程的大部分操作均是通過呼叫儲存引擎實現的介面來完成,這些介面被稱為handler api。查詢過程中的每一張表由乙個handler例項表示。實際上,mysql在查詢優化階段就為每一張表建立了乙個handler例項,優化器可以根據這些例項的介面來獲取表的相關資訊,包括表的所有列名、索引統計資訊等。儲存引擎介面提供了非常豐富的功能,但其底層僅有幾十個介面,這些介面像搭積木一樣完成了一次查詢的大部分操作。

返回結果給客戶端:

查詢執行的最後乙個階段就是將結果返回給客戶端。即使查詢不到資料,mysql仍然會返回這個查詢的相關資訊,比如該查詢影響到的行數以及執行時間等。

如果查詢快取被開啟且這個查詢可以被快取,mysql也會將結果存放到快取中。

結果集返回客戶端是乙個增量且逐步返回的過程。有可能mysql在生成第一條結果時,就開始向客戶端逐步返回結果集了。這樣服務端就無須儲存太多結果而消耗過多記憶體,也可以讓客戶端第一時間獲得返回結果。需要注意的是,結果集中的每一行都會以乙個滿足①中所描述的通訊協議的資料報傳送,再通過tcp協議進行傳輸,在傳輸過程中,可能對mysql的資料報進行快取然後批量傳送。

mysql整個查詢執行過程:

查詢優化(MySQL優化查詢)

關聯查詢太多join 設計缺陷或不得已的需求 資料庫伺服器調優及各個引數設定不適當 緩衝 執行緒數等 慢查詢日誌 找出執行速度慢的sql語句 慢查詢的開啟並捕獲 explain 慢sql分析 show profile查詢sql在mysql伺服器裡面的執行細節和生命週期情況 sql資料庫伺服器的引數調...

mysql統計查詢優化 Mysql查詢優化

效能涉及的層面很多,但是在操作層面,主要有表結構設計優化 索引優化和查詢優化 查詢的生命週期大致可以分為,從客戶端 到服務端 在伺服器上解析 生成執行計畫 執行 返回結果給客戶端 sql執行流程 具體優化技巧 1.消除外連線 2.消除子查詢 盡量用join代替子查詢,雖說mysql查詢優化器會進行優...

MySQL優化 查詢優化

在每乙個消耗大量時間的查詢中,都能看到一些不必要的額外操作 某些操作被額外地重複了很多次 某些操作執行得太慢等。優化查詢的目的就是減少和消除這些操作所花費的時間。查詢效能低下最基本的原因是訪問的資料太多。所以需要考慮是否向資料庫請求了不需要的資料 1 多表關聯時,或獲取單錶資料時,盡量避免不加思考地...