如何寫出高效能的MySQL查詢

2021-05-18 06:57:33 字數 2900 閱讀 8797

想寫這樣一篇文章很久了,但始終沒有下手。最近幫同事看了幾個查詢,而且自己也在考慮乙個索引系統的問題,所以今天就把這個寫了。介紹一下mysql的索引機制,還有一些mysql查詢的優化策略。鄙人才疏學淺,很可能說的不對,請路過的各位大俠批評指正,獻醜了。

------------------- jiajun.org 官方分割線 ---------------------

首先,說說mysql的索引儲存方式。mysql的索引一般是b-tree的結構儲存的,記憶體表也有hash索引,但是記憶體表的出鏡率似乎已經低到了用「可憐」來形容的程度,所以我們只考慮b-tree索引。

然後說說mysql的聯合索引。聯合索引對於乙個dbms總是非常重要的,因為每一條sql語句的條件子句是單條件的可能性很小,大多數情況下為組合條件,因此對於組合索引的依賴也就很強。mysql對於聯合索引的建立規則通過乙個例子說明:

對於乙個在列:col_a, col_b和col_c上的聯合索引,mysql會建立

index(col_a), index(col_a, col_b)和index(col_a, col_b, col_c)

這樣三個索引。

介紹完一些基本原理,我們來看mysql對於索引的選取規則和索引的建立原則(這些規則都是個人總結的,多**於網際網路,也有自己的經驗)。

對於單個索引,一般來說mysql的查詢優化器總能在若干查詢條件中選取效率較高的乙個使用,所以不必投入太多精力,一般來說查詢容易出現的問題容易出現在聯合索引。這裡以乙個兩列的索引為例,說明一些問題。

例如:idx_a_b (col_a, col_b)

建立做和索引的列進行or組合不可使用索引

例如:有條件

col_a = val_a or col_b = val_b

這個條件,是不可以使用idx_a_b索引的。然而同樣的查詢對於卻可以使用這樣的索引idx_a(col_a)或者idx_b(col_b)的,因此在建立索引的時候就要考慮到出鏡率最高的條件是什麼,建立怎樣的索引。而如果同時存在idx_a和idx_b兩個索引的話,mysql也只會選擇乙個使用,盡可能使用索引把結果集縮小,再在這個結果集中遍歷,使用其他條件篩選。

聯合索引對非字首列不生效

例如:條件col_b = val_b這個條件是不會使用這個索引的,因為索引idx_a_b的字首列是col_a。因此在建索引的時候,就要注意到,是否有很多使用這種條件的查詢,需要為col_b單獨建立索引。

對於組合索引,遇到範圍查詢則放棄使用剩餘部分

例如:條件

col_a = val_a and col_b = val_b

是可以使用整個索引,而對於

col_a between val_a_left and val_a_right and col_b = val_b

這個條件,只會使用索引的col_a這一部分,不會使用整個索引。對於這樣的查詢,我們有乙個優化策略,若col_a是乙個離散變數,則建議使用in代替between,例如,

col_a between 1 and 5 and col_b = val_b

建議寫成

col_a in (1, 2, 3, 4, 5) and col_b = val_b

這樣是可以使用整個idx_a_b的。

現在能想到的對於組合索引的使用就這些,還遠遠不夠全面,不過了解了這些原理,一般的查詢都是可以分析的。接下來介紹幾個策略性的sql優化。

盡量少的選擇列數

選擇你需要的列,不用圖省事就直接寫個select *,一來是為了減少通訊的開銷,再有就是如果你所選的列,都建立索引,那麼這次查詢就不會對錶資料進行任何操作,只查索引,就返回。

減少count(*), group by, distinct這樣的操作

這三種操作將進行大量的計算,對資料庫伺服器造成很大壓力,而且很慢。這樣的查詢能避免就避免,能快取就快取。

對於limit offset,若offset值較大,則採用分割結果集策略

limit offset操作一般用於翻頁,當offset值較小的時候直接使用limit offset效率搞,但當offset值增大到一定程度,這個查詢效率就會驟然降低。建議在大offset的情況下,採取這個策略:快取上一次結果的尾資料,在新的查詢中不使用offset,直接根據快取結果進行查詢。

例如:select * from tb limit 100 offset 500000;

offset值很大,建議這樣做:快取上一次結果的主鍵值id=id_val,sql改寫為:

select * from tb where id>id_val order by id limit 100

這條sql的效率將比上一條高很多倍。

策略性的優化也姑且先想到了這麼幾條,很不全面。綜合上面的這些查詢優化策略,我們還有幾個提高效能的系統配置和管理策略。例如:

定期重建索引

一張錶用的時間久了,資料頻繁更新,索引碎片會很多,降低查詢效率,重建索引可以整理這些碎片,大大提高查詢和寫入的效率。

配置恰當的query_buffer

如果你的機器有足夠大的記憶體,那多分給mysql一點吧,在一台8g記憶體的機器上,我們一般會分給mysql 4到6個g,query的快取會給你帶來驚喜的。

選擇恰當的引擎

常用的mysql引擎有innodb和myisam,前者更穩定且支援行級鎖,後者處理一般查詢效率更高。二者各有特點,一般我們會使用主從策略,主innodb,從myisam的做法。

在恰當的時候分表或分庫

mysql很強大,但對於200到300萬以上的資料進行處理,效能就開始有明顯的下降了,因此一般到這個數量級,就建議拆分資料了。

別讓查詢鏈結阻塞

mysql可以配置連線的超時時間,這個時間如果做得太長,甚至到了10min,那麼很可能發生這種情況,3000個鏈結都被佔滿而且sleep在哪,新鏈結進不來,導致無法正常服務。因此這個配置盡量配置乙個符合邏輯的值,60s或者120s等等。

當下能想到的也就是這些~~略顯膚淺,不過就寫到這裡吧,希望可以拋磚引玉,給大家乙個優化mysql的建議。

如何寫出高效能的MySQL查詢

想寫這樣一篇文章很久了,但始終沒有下手。最近幫同事看了幾個查詢,而且自己也在考慮乙個索引系統的問題,所以今天就把這個寫了。介紹一下 mysql的索引機制,還有一些mysql查詢的優化策略。鄙人才疏學淺,很可能說的不對,請路過的各位大俠批評指正,獻醜了。首先,說說 mysql的索引儲存方式。mysql...

mysql離散查詢 如何寫出高效能的MySQL查詢

想寫這樣一篇文章很久了,但始終沒有下手。最近幫同事看了幾個查詢,而且自己也在考慮乙個索引系統的問題,所以今天就把這個寫了。介紹一下mysql的索引機制,還有一些mysql查詢的優化策略。鄙人才疏學淺,很可能說的不對,請路過的各位大俠批評指正,獻醜了。首先,說說mysql的索引儲存方式。mysql的索...

如何寫出高效能SQL

在編寫一條查詢語句的時候,可以依據你要查詢資料表的資料總量,估算一下這條查詢大致需要遍歷多少行資料 如果遍歷行數在百萬以內的,只要不是每秒鐘都要執行幾十上百次的頻繁查詢,可以認為是安全的。遍歷資料行數在幾百萬的,查詢時間最少也要幾秒鐘,你就要仔細考慮有沒有優化的辦法。遍歷行數在千萬左右,是 mysq...