文章目錄
- mysql執行計劃
- 創建索引原則
- 1、有大量重複值、且經常有範圍查詢( > ,< ,> =,< =)和order by、group by發生的列,可考慮建立羣集索引;
- 2、經常同時存取多列,且每列都含有重複值可考慮建立組合索引;
- 3、組合索引要儘量使關鍵查詢形成索引覆蓋,其前導列一定是使用最頻繁的列;
- 4、表的主鍵、外鍵必須有索引;
- 5、區分度更高(同值的最少)的字段,建索引;
- 6、單表數據太少,不適合建索引。例如字典表
- 7、如果既有單字段索引,又有這幾個字段上的聯合索引,一般可以刪除聯合索引;
- 8、儘量使用前綴來索引
- 9、爲經常需要排序,分組和聯合操作的字段建立索引。
- 10、爲常作爲查詢條件的字段建立索引。
- 查詢語句優化原則
- 1、全值匹配
- 2、最佳左前綴法則
- 3、不在索引上做任何的操作(計算、函數、(自動or手動)類型轉換),會導致索引失效而變成全表掃描
- 4、存儲引擎不能使用索引中範圍條件(>、<、between等範圍查詢)右邊的列
- 5、儘量使用覆蓋索引
- 6、mysql在使用“不等於”、is null 、 is not null的時候不會使用索引,會進行全表掃描
- 7、少用or或者in,用or或者in時會導致索引失效
- 8、字符串不加單引號導致索引失效。
- 9、當取出的數據超過全表數據的20%時,不會使用索引
- 10、使用like時注意:
- 11、如果使用數字作爲字符,則數字需要加引號,否則mysql會自動在列上加數據類型轉換函數
- 12、字段加運算符不會使用索引。所以儘量把運算放在數值上
- 13、ORDER BY 子句只在以下的條件下使用索引:
- 14、只要能滿足你的需求,應儘可能使用更小的數據類型:例如使用MEDIUMINT代替INT
- 15、從 PROCEDURE ANALYSE() 取得建議
- 16、join 語法,儘量將小的表放在前面,在需要on的字段上,數據類型保持一致,並設置對應的索引,否則MySQL無法使用索引來join查詢
- 17、在大表上做大量更新時,如果會鎖全表,則需要拆分執行,避免長時間鎖住表,導致其他請求積累太多InnoDB 支持行鎖,但前提是Where子句需要建立索引,沒有索引也一樣是鎖全表
- 18、永遠用小結果集驅動大的結果集,小數據集的表先執行。
- 19、MySQL支持兩種方式的排序filesort和index,Using index 是指MySQL掃描索引本身完成排序。index效率高,filesort效率低。
- 20、 order by 滿足兩種情況會使用Using index。
- 21、group by 與order by 很類似,其實質是先排序後分組,遵照索引創建順序的最佳左前綴法則。注意Where高於having,能寫在where中的限定條件就不要去having限定了。
- 劃重點(∩_∩)
mysql執行計劃
注意:mysql各個版本的執行計劃的結果會有區別,需要根據具體的結果來做優化
explain各列釋義
id列
id列的編號是 select 的序列號,有幾個 select 就有幾個id,並且id的順序是按 select 出現的順序增長的。id越大越早執行。
select_type列
select_type 表示對應行是是簡單還是複雜的查詢。
複雜查詢分爲三類:簡單子查詢、派生表(from語句中的子查詢)、union 查詢。
該列的數據類型有:
- simple:簡單查詢。查詢不包含子查詢和union
- primary:複雜查詢中最外層的 select
- subquery:包含在 select 中的子查詢(不在 from 子句中)
- derived:包含在 from 子句中的子查詢。MySQL會將結果存放在一個臨時表中,也稱爲派生表
- union:在 union 中的第二個和隨後的 select
- union result:從 union 臨時表檢索結果的 select
table列
這一列表示 explain 的一行正在訪問哪個表。
當 from 子句中有子查詢時,table列是derivenN 格式,表示當前查詢依賴 id=N 的查詢,於是先執行 id=N 的查詢。當有 union 時,UNION RESULT 的 table 列的值爲 <union1,2>,1和2表示參與 union 的 select 行id。
type列
這一列表示關聯類型或訪問類型,即MySQL決定如何查找表中的行。
依次從最優到最差分別爲:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
type列各數值含義:
- NULL:mysql能夠在優化階段分解查詢語句,在執行階段用不着再訪問表或索引。例如:在索引列中選取最小值,可以單獨查找索引來完成,不需要在執行時訪問表
- const, system:mysql能對查詢的某部分進行優化並將其轉化成一個常量(可以看show warnings 的結果)。用於 primary key 或 unique key 的所有列與常數比較時,所以表最多有一個匹配行,讀取1次,速度比較快。
- eq_ref:primary key 或 unique key 索引的所有部分被連接使用 ,最多隻會返回一條符合條件的記錄。這可能是在 const 之外最好的聯接類型了,簡單的 select 查詢不會出現這種 type。
- ref:相比 eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前綴,索引要和某個值相比較,可能會找到多個符合條件的行。
- ref_or_null:類似ref,但是可以搜索值爲NULL的行。
- index_merge:表示使用了索引合併的優化方法。
- range:範圍掃描通常出現在 in(), between ,> ,<, >= 等操作中。使用一個索引來檢索給定範圍的行。
- index:和ALL一樣,不同就是mysql只需掃描索引樹,這通常比ALL快一些。
- ALL:即全表掃描,意味着mysql需要從頭到尾去查找所需要的行。通常情況下這需要增加索引來進行優化了
possible_keys列
這一列顯示查詢可能使用哪些索引來查找。
explain 時可能出現 possible_keys 有列,而 key 顯示 NULL 的情況,這種情況是因爲表中數據不多,mysql認爲索引對此查詢幫助不大,選擇了全表查詢。
如果該列是NULL,則沒有相關的索引。在這種情況下,可以通過檢查 where 子句看是否可以創造一個適當的索引來提高查詢性能,然後用 explain 查看效果。
key列
這一列顯示mysql實際採用哪個索引來優化對該表的訪問。
如果沒有使用索引,則該列是 NULL。如果想強制mysql使用或忽視possible_keys列中的索引,在查詢中使用 force index、ignore index。
key_len列
這一列顯示了mysql在索引裏使用的字節數,通過這個值可以算出具體使用了索引中的哪些列。
ref列
這一列顯示了在key列記錄的索引中,表查找值所用到的列或常量,常見的有:const(常量),func,NULL,字段名。
rows列
這一列是mysql估計要讀取並檢測的行數,注意這個不是結果集裏的行數。
Extra列
這一列展示的是額外信息。常見的重要值如下:
- distinct: 一旦mysql找到了與行相聯合匹配的行,就不再搜索了
- Using index:查詢的列被索引覆蓋(即覆蓋索引),並且where篩選條件是索引的前導列。這發生在對錶的請求列都是同一索引的部分的時候,返回的列數據只使用了索引中的信息,而沒有再去訪問表中的行記錄。是性能高的表現。
- Using where:查詢的列未被索引覆蓋,where篩選條件非索引前導列。
- Using index condition:與user where類似,查詢的列不完全被索引覆蓋,where 條件中是一個前導列的範圍。
- Using where;Using index:查詢的列被索引覆蓋,並且Where篩選條件是索引列之一但是不是索引的前導列,意味着無法直接通過索引查找符合條件的數據。
- NULL : 查詢的列未被索引覆蓋,where篩選條件是索引前導列。意味着用到了索引,但是部分字段未被索引覆蓋,必須通過回表來實現。
- Using temporary:mysql需要創建一張臨時表來處理查詢。出現這種情況一般是要進行優化的,首先是想到用索引來優化。
- Using filesort:mysql 會對結果使用一個外部索引排序,而不是按索引次序從表裏讀取行。此時mysql會根據聯接類型瀏覽所有符合條件的記錄,並保存排序關鍵字和行指針,然後排序關鍵字並按順序檢索行信息。這種情況下一般也是要考慮使用索引來優化的。
創建索引原則
熟記這些創建索引原則,但具體效果要具體分析。
1、有大量重複值、且經常有範圍查詢( > ,< ,> =,< =)和order by、group by發生的列,可考慮建立羣集索引;
2、經常同時存取多列,且每列都含有重複值可考慮建立組合索引;
3、組合索引要儘量使關鍵查詢形成索引覆蓋,其前導列一定是使用最頻繁的列;
索引雖有助於提高性能但不是索引越多越好,恰好相反過多的索引會導致系統低效。用戶在表中每加進一個索引,維護索引集合就要做相應的更新工作。
4、表的主鍵、外鍵必須有索引;
5、區分度更高(同值的最少)的字段,建索引;
6、單表數據太少,不適合建索引。例如字典表
7、如果既有單字段索引,又有這幾個字段上的聯合索引,一般可以刪除聯合索引;
8、儘量使用前綴來索引
其實一般情況下我們也不會在字段類型爲TEXT和BLOG類型上加索引。
如果索引字段的值很長,最好使用值的前綴來索引。例如,TEXT和BLOG類型的字段,進行全文檢索會很浪費時間。如果只檢索字段的前面的若干個字符,這樣可以提高檢索速度。
9、爲經常需要排序,分組和聯合操作的字段建立索引。
10、爲常作爲查詢條件的字段建立索引。
查詢語句優化原則
優化方法不止下述提到的這些。有碰到優化方法就要記錄和驗證(一定要驗證,而不是去記,很多博客寫得並不嚴謹)。
以下的方法如果博主有驗證通過了會給完整案例(包括建表、數據量、數據庫執行計劃等信息),如沒有,就是僅供參考而已,優化原則均來自博主同事與網上博客。
這些優化要結合mysql的數據結構,要自己去看explain(執行計劃)。mysql還有他自己的優化,例如:數據量小的時候明明用了這些優化方法還是不走索引。所以要具體問題具體分析。
熟記這些優化原則,但具體效果要具體分析。
1、全值匹配
如果用到了聯合索引,那麼一般情況下,最好是將聯合索引的各字段都用到查詢條件中。
2、最佳左前綴法則
如果索引了多列,要遵守最左前綴法則。指的是查詢從索引的最左前列開始並且不跳過索引中的列。
3、不在索引上做任何的操作(計算、函數、(自動or手動)類型轉換),會導致索引失效而變成全表掃描
4、存儲引擎不能使用索引中範圍條件(>、<、between等範圍查詢)右邊的列
舉例:
name、age、title爲聯合索引,如果是下面的查詢語句,那麼只會用到name、age兩個索引。
SELECT * FROM employees WHERE name = 'qitian' AND age>18 AND title= '經理'
5、儘量使用覆蓋索引
就是查詢的結果集都爲索引字段,那麼就是覆蓋索引。
6、mysql在使用“不等於”、is null 、 is not null的時候不會使用索引,會進行全表掃描
7、少用or或者in,用or或者in時會導致索引失效
a爲主鍵,b爲索引
select a, b from test where b in ( 'x1', 'x2','x3')
正常情況下,上述sql語句不會走索引。
如果類似的查詢語句必須走索引的話
可以考慮用union來聯結,分開查詢就可以走索引了。
select a, b from test where b ='x1'
union
select a, b from test where b ='x2'
union
select a, b from test where b ='x3'
8、字符串不加單引號導致索引失效。
9、當取出的數據超過全表數據的20%時,不會使用索引
10、使用like時注意:
不使用索引:
like ‘%L%’
使用索引:
like ‘L%’
11、如果使用數字作爲字符,則數字需要加引號,否則mysql會自動在列上加數據類型轉換函數
不使用索引
where mobile=18868886888
使用索引
where mobile=’18868886888’
12、字段加運算符不會使用索引。所以儘量把運算放在數值上
不使用索引:
SELECT ACCOUNT_NAME, AMOUNT FROM TRANSACTION WHERE AMOUNT + 3000 >5000;
使用索引:
SELECT ACCOUNT_NAME, AMOUNT FROM TRANSACTION WHERE AMOUNT > 2000 ;
13、ORDER BY 子句只在以下的條件下使用索引:
ORDER BY中所有的列必須包含在相同的索引中並保持在索引中的排列順序.
ORDER BY中不能既有ASC也有DESC
例如:
alter table test1 add index(a,b);
alter table test1 add index©;
不使用索引:
select * from test1 order by a,c; 不在一個索引中
select * from test1 order by b; 沒有出現組合索引的第一列
select * from test1 order by a asc, b desc; 混合ASC和DESC
select * from test1 where a=1 order by c; where和order by用的不是同一個索引,where使用索引,order by不使用。
使用索引:
select * from test1 order by a,b;
select * from test1 order where a=1 order by b;
select * from test1 order where a=1 order by a,b;
select * from test1 order by a desc, b desc;
select * from test1 where c=1 order by c;
14、只要能滿足你的需求,應儘可能使用更小的數據類型:例如使用MEDIUMINT代替INT
15、從 PROCEDURE ANALYSE() 取得建議
PROCEDURE ANALYSE() 會讓 MySQL 幫你去分析你的字段和其實際的數據,並會給你一些有用的建議。只有表中有實際的數據,這些建議纔會變得有用,因爲要做一些大的決定是需要有數據作爲基礎的。
表中需要有數據,這樣mysql纔好給出建議,結果集的最後一列就是mysql認爲應該改用的數據類型建議。
16、join 語法,儘量將小的表放在前面,在需要on的字段上,數據類型保持一致,並設置對應的索引,否則MySQL無法使用索引來join查詢
17、在大表上做大量更新時,如果會鎖全表,則需要拆分執行,避免長時間鎖住表,導致其他請求積累太多InnoDB 支持行鎖,但前提是Where子句需要建立索引,沒有索引也一樣是鎖全表
18、永遠用小結果集驅動大的結果集,小數據集的表先執行。
19、MySQL支持兩種方式的排序filesort和index,Using index 是指MySQL掃描索引本身完成排序。index效率高,filesort效率低。
20、 order by 滿足兩種情況會使用Using index。
- order by語句使用索引最左前列。
- 使用Where子句與order by 子句條件列組合滿足索引最左前列
21、group by 與order by 很類似,其實質是先排序後分組,遵照索引創建順序的最佳左前綴法則。注意Where高於having,能寫在where中的限定條件就不要去having限定了。
劃重點(∩_∩)
本人程序媛一枚,因爲離港澳較近,週末兼職港澳人肉代購。
歡迎各位大佬添加本人微信,還會經常有點贊活動送價值不菲的小禮品哦。
即使現在不需要代購,等以後有了女(男)朋友、有了寶寶就肯定會需要的嘍。
動動手指頭,掃碼一下,就當是對本博文的支持嘛,也是對一個平凡、勤勞、勇敢、秀外慧中等等優點的程序媛莫大的支持哈。