慢查詢優化是勢在必行的,可是要對mysql慢查詢進行優化,首先要知道慢查詢的語句和mysql數據庫的運行狀態。mysql
對數據庫慢查詢進行排查以前先了解一下mysql的幾個命令,有助於幫助咱們定位慢查詢語句:sql
show status; // 查詢mysql數據庫的一些運行狀態
show status like 'uptime'; // 查看mysql數據庫啓動多長時間,myisam存儲引擎長時間啓動須要進行碎片整理
show status like 'slow_queries'; //查看慢查詢的數量
show variables like 'long_query_time';//查看慢查詢的時間
set long_query_time = 0.5;//設置慢查詢的時間,單位秒(s)
Explain select * from notes where id = 137 ;//將Explain命令放到查詢命令前便可
返回的結果以下:數據庫
2.返回結果字段說明:緩存
id:SELECT的查詢序列號。
select_type:表示SELECT語句的類型。有如下幾種取值: SIMPLE:表示簡單杳詢,其中不包括鏈接查詢和子查詢; PRIMARY:表示主查詢,或者最外層的查詢語句; UNION:表示鏈接查詢的第2個或後面的查詢語句; DEPENDENT UNION:鏈接查詢中的第2個或後面的SELECT語句,取決於外面的查詢; UNION RESULT:鏈接查詢的結果; SUBQUERY:子查詢中的第一個SELECT語句; DEPENDENT SUBQUERY:子查詢中的第一個SELECT,取決於外面的查詢; DERIVED:導出表的SELECT (FROM語句的子查詢)。
table:表示查詢的表。
type:表示表的鏈接類型。下面按照從最優類型到最差類型的順序給出各類鏈接類型: (1) system 該表僅有一行的系統表。這是const鏈接類型的一個特例。 (2) const 數據表最多隻有一個匹配行,它將在查詢開始時被讀取,並在餘下的査詢優化中做爲常量對待。
const表查詢速度很快,由於它們只讀取一次。const用於使用常數值比較PRIMARY KEY或UNIQUE索引的全部部分的場合。 好比: SELECT * from tb1_name WHERE primary_key=1; SELECT * from tb1_name WHERE primary_key_part1=1 AND primary_key_part2=2 (3) eq_ref 對於每一個來自前面的表的行組合,從該表中讀取一行。當一個索引的全部部分都在查詢中使用,而且索引是UNIQUE或者PRIMARY KEY時,便可使用這種類型。 eq_ref能夠用於使用「=」操做符比較帶索引的列。比較值能夠爲常量或者一個在該表前面所讀取的表的列的表達式。 好比: SELECT * FROM ref_table,other_table WHERE ref_table.key_cloumn = other_table.cloumn; SELECT * FROM ref_table,other_tbale WHERE ref_table.key_cloumn_part1 = other_table.cloumn AND ref_table.key_cloumn_part2 = 1; (4)ref 對於來自前面的表的任意組合,將從該表中讀取全部匹配的行。
這種類型用於索引既不是UNIQUE也不是PRIMARY KEY的狀況,或者查詢中使用了索引列在左子集,既索引中左邊的部分列組合。ref能夠用於使用=或者<=>操做符的帶索引的列。 好比: select * from ref_table where key_column=expr; select * from ref_table,other_table where ref_table.key_column=other_table.column; select * from ref_table,other_table where ref_table.key_column_part1=other_table.column and ref_table.key_column_part2=1; (5)ref_or_null 這種鏈接類型相似ref,不一樣的是mysql會在檢索的時候額外的搜索包含null值的記錄。在解決子查詢中常用該連接類型的優化。 好比: select * from ref_table where key_column=expr or key_column is null; (6)index_merge 該連接類型表示使用了索引合併優化方法。在這種狀況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。 (7)unique_subquery 該類型替換了下面形式的IN子查詢的ref: value in (select primary_key from single_table where some_expr) (8)index_subquery 這種鏈接類型相似 unique_subquery。能夠替換IN子查詢,不過它用於在子查詢中沒有惟一索引的狀況下, 例如如下形式: value in (select key_column from single_table where some_expr) (9)range 只檢索給定範圍的行,使用一個索引來選擇行。key列顯示使用了哪一個索引。ken_len包含所使用索引的最長關鍵元素。
當使用 =, <>, >,>=, <, <=, is null, <=>, between, 或 in操做符,用常量比較關鍵字列時,類型爲range。 下面介紹幾種檢索制定行的狀況: select * from tbl_name where key_column = 10; select * from tbl_name where key_column between 10 and 20; select * from tbl_name where key_column in (10,20,30); select * from tbl_name where key_part1= 10 and key_part2 in (10,20,30); (10)index 鏈接類型跟ALL同樣,不一樣的是它只掃描索引樹。它一般會比ALL快點,由於索引文件一般比數據文件小。 (11)ALL 對於前面的表的任意行組合,進行完整的表掃描。
若是第一個表沒有被標識爲const的話就不大好了,在其餘狀況下一般是很是糟糕的。正常地,能夠經過增長索引使得能從表中更快的取得記錄以免ALL。
possible_keys:是指MySQL在搜索表記錄時可能使用哪一個索引。
若是這個字段的值是NULL,就表示沒有索引被用到。
這種狀況下,就能夠檢查WHERE子句中哪些字段哪些字段適合增長索引以提升查詢的性能。
建立一下索引,而後再用explain 檢查一下。
key:顯示MySQL實際上要用的索引。
當沒有任何索引被用到的時候,這個字段的值就是NULL。
想要讓MySQL強行使用或者忽略在 possible_keys字段中的索引列表,能夠在查詢語句中使用關鍵字force index, use index或 ignore index。參考SELECT語法。
key_len:顯示mysql使用索引的長度。當key 字段的值爲NULL時,索引的長度就是NULL。注意,key_len的值能夠告訴你在聯合索引中MySQL會真正使用了哪些索引。
ref:表示使用哪一個列或常數與索引一塊兒來查詢記錄。
rows:顯示MySQL在表中進行查詢時必須檢查的行數。
Extra:顯示查詢中mysql的附加信息。如下是這個字段的幾個不一樣值的解釋:
(1) distinct MySQL當找到當前記錄的匹配聯合結果的第一條記錄以後,就再也不搜索其餘記錄了。
(2) not exists MySQL在查詢時作一個LEFT JOIN優化時,當它在當前表中找到了和前一條記錄符合LEFT JOIN條件後,就再也不搜索更多的記錄了。
好比:select * from t1 left join t2 on t1.id=t2.id where t2.id is null; 假使 t2.id 定義爲 not null。
這種狀況下,MySQL將會掃描表 t1而且用 t1.id 的值在 t2 中查找記錄。
當在 t2中找到一條匹配的記錄時,這就意味着 t2.id 確定不會都是null,就不會再在 t2 中查找相同id值的其餘記錄了。
也能夠這麼說,對於 t1 中的每一個記錄,mysql只須要在t2 中作一次查找,而無論在 t2 中實際有多少匹配的記錄。 (3)range checked for each record (index map: #) mysql沒找到合適的可用的索引。
取代的辦法是,對於前一個表的每個行鏈接,它會作一個檢驗以決定該使用哪一個索引(若是有的話),而且使用這個索引來從表裏取得記錄。
這個過程不會很快,但總比沒有任何索引時作錶鏈接來得快。 (4)using filesort MySQL須要額外的作一遍從已排好的順序取得記錄。
排序程序根據鏈接的類型遍歷全部的記錄,而且將全部符合where條件的記錄的要排序的鍵和指向記錄的指針存儲起來。
這些鍵已經排完序了,對應的記錄也會按照排好的順序取出來。
(5)using index 字段的信息直接從索引樹中的信息取得,而再也不去掃描實際的記錄。這種策略用於查詢時的字段是一個獨立索引的一部分。 (6)using temporary mysql須要建立臨時表存儲結果以完成查詢。這種狀況一般發生在查詢時包含了group by和order by子句,它以不一樣的方式列出了各個字段。 (7)using where where子句將用來限制哪些記錄匹配了下一個表或者發送給客戶端。
除非你特別地想要取得或者檢查表種的全部記錄,不然的話當查詢的extra字段值不是using where而且錶鏈接類型是all或index時可能表示有問題。 若是你想要讓查詢儘量的快,那麼就應該注意extra字段的值爲using filesort和using temporary的狀況。
(1) 分解表服務器
對於字段比較多的表,若是有些字段的使用頻率很低,能夠將這些字段分離出來造成新表。由於當一個表的數據量很大時,會因爲使用頻率低的字段的存在而變慢。數據庫設計