對於索引我總結三大原則:mysql
基本掌握這三條,對於索引的優化理論上是沒有問題了。sql
通常在where條件中兩個及以上字段時,咱們會建聯合索引。 高效使用索引的首要條件是知道什麼樣的查詢會使用到索引,這個問題和B+Tree中的「最左前綴原理」有關,下面經過例子說明最左前綴原理。 MySQL中的索引能夠以必定順序引用多個列,這種索引叫作聯合索引,通常的,一個聯合索引是一個有序元組<a1,a2,a3...an>,其中各個元素均爲數據表的一列,實際上要嚴格定義索引須要用到關係代數。另外,單列索引能夠當作聯合索引元素數爲1的特例 最左前綴是一個很重要的原則。 mysql會從左至右匹配,直到遇到範圍查找(> < like between)就中止。 如: select * from table1 where a=1 and b=2 and c<3 and d=9 ; 創建的聯合索引爲:(a,b,c,d) 實際使用的索引爲(a,b,c)。由於遇到了c<3就中止了,d列就沒有用上。 前面講過聯合索引是有序元組, 則mysql實際建的索引爲:(a) (a,b) (a,b,c) (a,b,c,d)。 舉個例子:where b=2 and c=3 and d=9 ;按照最左匹配原則,這個條件就無法走索引了,首先必須有a。 =,in能夠亂序,查詢優化器會幫你優化成索引能夠識別的形式。也就是說,where b=2 and a=1 and c<3 使用的索引任然爲(a,b,c)組合。 回到線上案例: 索引:idx_whid_distributionorderid(wh_id,distribution_order_id) 索引組合 (wh_id) ,(wh_id,distribution_order_id) 至關於建了一個wh_id 的單列索引,也就是說當你要根據wh_id查詢時,是不須要再新建索引了。數據庫
儘可能擴展索引、不要新建索引 mysql目前主要索引有:FULLTEXT,HASH,BTREE 好的索引能夠提升咱們的查詢效率,很差的索引不但不會起做用,反而給DB帶來負擔,基於BTREE結構,插入、修改都會從新調整索引結構,存儲成本增長,寫效率下降,同時DB系統也要消耗資源去維護。 基於剛纔的最左匹配原則,儘可能在原有基礎上擴展索引,不要新增索引。 能用單索引,不用聯合索引;能用窄索引,不用寬索引;能複用索引,不新建索引。 回到線上案例: nc_tms_order、ct_order看看分別有哪些索引工具
看到這裏我開始凌亂,好像什麼字段均可以加索引。 爲此專門針對ct_order表兩個具備比較性的索引作了性能測試,ct_order_code,lc_order_code區分度都是很是高的字段,前者是好於後者(聯合station_id並無起到太多優化做用)。 idx_ct_order_code(ct_order_code), idx_ct_order_lc_order_code(station_id,lc_order_code) 那麼接下來咱們說說那些字段適合建索引。性能
選擇區分度高列作索引 什麼是區分度高的字段呢? 通常兩種狀況不建議建索引: 一、一兩千條甚至幾百條,不必建索引,讓查詢作全表掃描就行了。 由於不是你建了就必定會走索引,執行計劃會選擇一個最優的方式,msql輔助索引的葉子節點並不直接存儲實際數據,只是主建ID,再經過主鍵索引二次查找。這麼一來全表可能頗有可能效率更高。 二、索引選擇性較低的狀況。 所謂選擇性(Selectivity),是指不重複的索引值(也叫基數,Cardinality)與表記錄數(#T)的比值。測試
Index Selectivity = Cardinality / #T 顯然選擇性的取值範圍爲(0, 1],選擇性越高的索引價值越大,這是由B+Tree的性質決定的。 回到線上案例 wh_id 最好不用作索引字段,這個和性別男、女做爲索引字段沒區別: SELECT count(DISTINCT(wh_id))/count(*) AS Selectivity FROM nc_tms_order_0340 nc_tms_order;優化
0ui
選擇性不足0.0001(精確值爲0.00000666),按Selectivity值越大價值越大原則,實在沒有什麼必要爲其單獨建索引。 再看下distribution_order_id 單列索引。 SELECT count(DISTINCT(distribution_order_id))/count(*) AS Selectivity FROM nc_tms_order_0340 nc_tms_order;unix
0.0030code
Selectivity = 0.0030 ,比以前有所優化,但其實不不是特別理想。 聯合索引 SELECT count(DISTINCT(concat(wh_id,distribution_order_id)))/count(*) AS Selectivity FROM nc_tms_order_0340 nc_tms_order;
0.0030
Selectivity = 0.0030 從值來看,這裏建聯合索引的價值並非特別大。一個distrubution_id 搞定。 那麼咱們在建一個索引或聯合索引的時候拿不許的時候能夠先計算下選擇性值以及經過explain測試。 通常狀況,status、is_deleted列不建議建索引。 建立複合索引,須要注意把區分度最大的放到最前面。也就是值越大的放前面,固然需根據時間場景和sql經過執行計劃進行優化。 前綴索引 有一種與索引選擇性有關的索引優化策略叫作前綴索引,就是用列的前綴代替整個列做爲索引key,當前綴長度合適時,能夠作到既使得前綴索引的選擇性接近全列索引,同時由於索引key變短而減小了索引文件的大小和維護開銷。
好比from_unixtime(create_time) = ’2017-11-11’就不能使用到索引,語句應該寫成create_time = unix_timestamp(’2017-11-11’);
主鍵最好使用自增型,保證數據連續性(mysql innodb 主鍵默認採用b+tree,索引和數據放在同一個btree中),不要使用uuid、hash、md5等 不要使用前匹配的like查詢,會致使索引失效。可使用後匹配like,如"xxx%"。 在字符串列上建立索引,儘可能使用前綴索引。前綴基數根據具體業務,在匹配度和存儲量(索引的存儲量)以前作一個平衡。 不要使用 not inlike,會致使索引失效。not in能夠用not exists替換。in和or所在列最好有索引 說了這麼多留action吧,你們回去看看ct_order,nc_tms_order看看如何優化吧。 其實數據庫索引調優,光靠理論是不行的,須要結合實際狀況。MySQL機制複雜,如查詢優化策略和各類引擎的實現差別等都會使狀況變複雜。咱們在瞭解這些原則和基礎之上,要不斷的實踐和總結,從而真正達到高效使用MySQL索引的目的。 執行計劃explain命令 explain 是sql優化神奇。 公司IDB的執行計劃被包裝過了,除了被動查慢sql調優上看到,一直沒找主動作執行計劃的地方,有知道的能夠告訴我下。 如下均爲工具介紹,可留作備查。 explain用法 EXPLAIN tbl_name或:EXPLAIN [EXTENDED] SELECT select_options 舉例 mysql> explain select * from event;
+—-+————-+——-+——+—————+——+———+——+——+——-+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+—-+————-+——-+——+—————+——+———+——+——+——-+
| 1 | SIMPLE | event | ALL | NULL | NULL | NULL | NULL | 13 | |
+—-+————-+——-+——+—————+——+———+——+——+——-+
1 row in set (0.00 sec) 各個屬性的含義 id:select查詢的序列號
select_type:select查詢的類型,主要是區別普通查詢和聯合查詢、子查詢之類的複雜查詢。
table:輸出的行所引用的表。
type:聯合查詢所使用的類型。
type顯示的是訪問類型,是較爲重要的一個指標,結果值從好到壞依次是: system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL 通常來講,得保證查詢至少達到range級別,最好能達到ref。 就type進行詳細的介紹:all : 即全表掃描
index : 按索引次序掃描,就type進行詳細的介紹: System,const,eq_ref,ref,range,index,all
all : 即全表掃描
index : 按索引次序掃描,先讀索引,再讀實際的行,結果仍是全表掃描,主要優勢是避免了排序。由於索引是排好的。
range:以範圍的形式掃描。
explain select * from a where a_id > 1\G
ref:非惟一索引訪問(只有普通索引)
create table a(a_id int not null, key(a_id)); insert into a values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10); mysql> explain select * from a where a_id=1\G
eq_ref:使用惟一索引查找(主鍵或惟一索引)
const:常量查詢
當出現using index時,表示sql使用覆蓋索引,性能較好,而當出現using filesort、using temporary、using where時,查詢須要優化。 先讀索引,再讀實際的行,結果仍是全表掃描,主要優勢是避免了排序。由於索引是排好的。
range:以範圍的形式掃描。
explain select * from a where a_id > 1\G
ref:非惟一索引訪問(只有普通索引)
create table a(a_id int not null, key(a_id)); insert into a values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10); mysql> explain select * from a where a_id=1\G eq_ref:使用惟一索引查找(主鍵或惟一索引)
const:常量查詢
當出現using index時,表示sql使用覆蓋索引,性能較好,而當出現using filesort、using temporary、using where時,查詢須要優化。
possible_keys:指出MySQL能使用哪一個索引在該表中找到行。若是是空的,沒有相關的索引。這時要提升性能,可經過檢驗WHERE子句,看是否引用某些字段,或者檢查字段不是適合索引。
key:顯示MySQL實際決定使用的鍵。若是沒有索引被選擇,鍵是NULL。
key_len:顯示MySQL決定使用的鍵長度。若是鍵是NULL,長度就是NULL。文檔提示特別注意這個值能夠得出一個多重主鍵裏mysql實際使用了哪一部分。
ref:顯示哪一個字段或常數與key一塊兒被使用。
rows:這個數表示mysql要遍歷多少數據才能找到,在innodb上是不許確的。
Extra:若是是Only index,這意味着信息只用索引樹中的信息檢索出的,這比掃描整個表要快。
若是是where used,就是使用上了where限制。 若是是impossible where 表示用不着where,通常就是沒查出來啥。 若是此信息顯示Using filesort或者Using temporary的話會很吃力,WHERE和ORDER BY的索引常常沒法兼顧,若是按照WHERE來肯定索引,那麼在ORDER BY時,就必然會引發Using filesort,這就要看是先過濾再排序划算,仍是先排序再過濾划算。