mysql查詢優化詳解

2021-10-08 07:01:55 字數 3804 閱讀 4852

在編寫快速的查詢之前,需要清楚一點,真正重要的是響應時間,而且要知道在整個sql語句的執行過程中每個步驟都花費了多長時間,要知道哪些步驟是拖垮執行效率的關鍵步驟,想要做到這點,必須要知道查詢的生命週期,然後進行優化,不同的應用場景有不同的優化方式,不要一概而論,具體情況具體分析

如果乙個sql查詢比較慢,可能因為多方面的原因:

網路、cpu、io、上下文切換、系統呼叫、生成統計資訊/臨時表、鎖等待時間
查詢效能低下的主要原因是訪問的資料太多,某些查詢不可避免的需要篩選大量的資料,我們可以通過減少訪問資料量的方式進行優化

是否向資料庫請求了不需要的資料?

我們常常會誤以為mysql會只返回需要的資料,實際上mysql卻是先返回全部結果再進行計算,在日常的開發習慣中,經常是先用select語句查詢大量的結果,然後獲取前面的n行後關閉結果集。

優化方式是在查詢後面新增limit

select * from actor inner join film_actor using(actor_id) inner join film using(film_id) where film.title=『academy dinosaur』;

select actor.* from actor…;

在公司的企業需求中,禁止使用select *,雖然這種方式能夠簡化開發,但是會影響查詢的效能,所以盡量不要使用

如果需要不斷的重複執行相同的查詢,且每次返回完全相同的資料,因此,基於這樣的應用場景,我們可以將這部分資料快取起來,這樣的話能夠提高查詢效率

在解析乙個查詢語句之前,如果查詢快取是開啟的,那麼mysql會優先檢查這個查詢是否命中查詢快取中的資料,如果查詢恰好命中了查詢快取,那麼會在返回結果之前會檢查使用者許可權,如果許可權沒有問題,那麼mysql會跳過所有的階段,就直接從快取中拿到結果並返回給客戶端

mysql查詢完快取之後會經過以下幾個步驟:解析sql、預處理、優化sql執行計畫,這幾個步驟出現任何的錯誤,都可能會終止查詢

mysql通過關鍵字將sql語句進行解析,並生成一顆解析樹,mysql解析器將使用mysql語法規則驗證和解析查詢,例如驗證使用使用了錯誤的關鍵字或者順序是否正確等等,預處理器會進一步檢查解析樹是否合法,例如表名和列名是否存在,是否有歧義,還會驗證許可權等等

查詢優化器會統計每個表或者索引的頁面個數、索引的基數、索引和資料行的長度、索引的分布情況

但是在某些情況下mysql可能會選擇到錯誤的執行計畫,原因如下:

innodb因為其mvcc的架構,並不能維護乙個資料表的行數的精確統計資訊

有時候某個執行計畫雖然需要讀取更多的頁面,但是他的成本卻更小,因為如果這些頁面都是順序讀或者這些頁面都已經在記憶體中的話,那麼它的訪問成本將很小,mysql層面並不知道哪些頁面在記憶體中,哪些在磁碟,所以查詢之際執行過程中到底需要多少次io是無法得知的

mysql的優化是基於成本模型的優化,但是有可能不是最快的優化

執行儲存過程或者使用者自定義函式的成本

優化器的優化策略
直接對解析樹進行分析,並完成優化

動態優化與查詢的上下文有關,也可能跟取值、索引對應的行數有關

mysql對查詢的靜態優化只需要一次,但對動態優化在每次執行時都需要重新評估

優化器的優化型別

資料表的關聯並不總是按照在查詢中指定的順序進行,決定關聯順序時優化器很重要的功能

索引和列是否可以為空通常可以幫助mysql優化這類表示式:例如,要找到某一列的最小值,只需要查詢索引的最左端的記錄即可,不需要全文掃瞄比較

explain select film.film_id,film_actor.actor_id from film inner join film_actor using(film_id) where film.film_id = 1

mysql在某些情況下可以將子查詢轉換一種效率更高的形式,從而減少多個查詢多次對資料進行訪問,例如將經常查詢的資料放入到快取中

如果兩個列的值通過等式關聯,那麼mysql能夠把其中乙個列的where條件傳遞到另乙個上:

explain select film.film_id from film inner join film_actor using(film_id) where film.film_id > 500;

這裡使用film_id欄位進行等值關聯,film_id這個列不僅適用於film表而且適用於film_actor表

explain select film.film_id from film inner join film_actor using(film_id) where film.film_id > 500 and film_actor.film_id > 500;

關聯查詢

join的實現原理

排序演算法的優化

第一次資料讀取是將需要排序的字段讀取出來,然後進行排序,第二次是將排好序的結果按照需要去讀取資料行。

這種方式效率比較低,原因是第二次讀取資料的時候因為已經排好序,需要去讀取所有記錄而此時更多的是隨機io,讀取資料成本會比較高

兩次傳輸的優勢,在排序的時候儲存盡可能少的資料,讓排序緩衝區可以盡可能多的容納行數來進行排序操作

先讀取查詢所需要的所有列,然後再根據給定列進行排序,最後直接返回排序結果,此方式只需要一次順序io讀取所有的資料,而無須任何的隨機io,問題在於查詢的列特別多的時候,會占用大量的儲存空間,無法儲存大量的資料

當需要排序的列的總大小超過max_length_for_sort_data定義的位元組,mysql會選擇雙次排序,反之使用單次排序,當然,使用者可以設定此引數的值來選擇排序的方式

其他方面的優化

myisam引擎會維護乙個字段可以直接獲取到count(),但是前提是不帶任何where條件

count(1)、count()沒有任何效率上的區別,建議使用count(*)

確保on或者using子句中的列上有索引,在建立索引的時候就要考慮到關聯的順序

當表a和表b使用列c關聯的時候,如果優化器的關聯順序是b、a,那麼就不需要再b表的對應列上建上索引,沒有用到的索引只會帶來額外的負擔,一般情況下來說,只需要在關聯順序中的第二個表的相應列上建立索引

確保任何的groupby和order by中的表示式只涉及到乙個表中的列,這樣mysql才有可能使用索引來優化這個過程

子查詢的優化最重要的優化建議是盡可能使用關聯查詢代替

優化此類查詢的最簡單的辦法就是盡可能地使用覆蓋索引,而不是查詢所有的列

除非確實需要伺服器消除重複的行,否則一定要使用union all,因此沒有all關鍵字,mysql會在查詢的時候給臨時表加上distinct的關鍵字,這個操作的代價很高

MySQL 查詢優化詳解

mysql客戶端 服務端通訊,查詢快取,查詢優化處理,查詢執行引擎,返回客戶端 mysql 客戶端與服務端的通訊方式是 半雙工 半雙工 雙向通訊,同時只能接收或者傳送,無法同時操作 對於乙個mysql連線,或者說乙個執行緒,時刻都有乙個狀態來表示這個連線正在做什麼,檢視命令 show full pr...

mysql查詢優化explain命令詳解

mysql查詢優化的方法有很多種,explain是工作當中用的比較多的一種檢查方式。explain翻譯即解釋,就是看mysql語句的查詢解釋計畫,從解釋計畫我們能很清楚的看到解釋的語句有沒有合理用到索引,掃瞄了多少行數,有沒有觸及全表掃瞄 用到臨時表等影響慢查詢的原因。使用很簡單,如 explain...

查詢優化(MySQL優化查詢)

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