mysql离散查询_如何写出高性能的MySQL查询
作者:會寫代碼的豬 發布時間:December 25, 2009 分類:豬在寫代碼
想寫這樣一篇文章很久了,但始終沒有下手。最近幫同事看了幾個查詢,而且自己也在考慮一個索引系統的問題,所以今天就把這個寫了。介紹一下MySQL的索引機制,還有一些MySQL查詢的優化策略。鄙人才疏學淺,很可能說的不對,請路過的各位大俠批評指正,獻丑了。
首先,說說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查询的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle数据库主键消失,oracle
- 下一篇: c++ 不能分配给为0的数组_【嵌入式C