生產上有一個運行了個多月的項目,隨着數據越來越多,查詢就變得越來越慢,按理說STATUS這個字段也加了索引,爲什麼會這麼慢呢?之前有一篇文章已經講解過索引的最左原則,今天講講爲什麼聯合索引失效了。
我們執行如下語句:SHOW INDEX FROM T_table_name 查看該表的索引情況:
Table:表名稱
Non_unique:如果索引不能包括重複詞,則爲0。如果可以,則爲1。
Key_name:索引名稱
Seq_in_index:索引中的列序列號,從1開始(最左原則與該順序掛鉤,需注意)
Column_name:列名稱
Collation:列以什麼方式存儲在索引中,在MySQL中,有值‘A’(升序)或NULL(無分類)
Cardinality:索引中唯一值的數目的估計值。通過運行ANALYZE TABLE或myisamchk -a可以更新。基數根據被存儲爲整數的統計數據來計數,所以即使對於小型表,該值也沒有必要是精確的。基數越大,當進行聯合時,MySQL使用該索引的機會就越大
Sub_part:如果列只是被部分地編入索引,則爲被編入索引的字符的數目。如果整列被編入索引,則爲NULL
Packed:指示關鍵字如何被壓縮。如果沒有被壓縮,則爲NULL。
Null:如果列含有NULL,則含有YES,如果沒有,則該列含有NO。
Index_type:用過的索引方法(BTREE, FULLTEXT, HASH, RTREE)
我們發現,STATUS字段在seq_in_index中排在了第5位,按照索引的最左原則,直接WHERE STATUS='1'時,索引便會失效:
我們看看type類型,竟然是all,這就意味着進行了全表掃描(索引失效),那麼type是什麼意思呢?MySQL的官網解釋非常簡潔,只用了3個單詞:連接類型(the join type),它描述了找到所需數據使用的掃描方式,也有人稱呼它爲訪問類型。
最爲常見的掃描方式有:
system:系統表,少量數據,往往不需要進行磁盤IO;
const:常量連接;
eq_ref:主鍵索引(primary key)或者非空唯一索引(unique not null)等值掃描;
ref:非主鍵非唯一索引等值掃描;
range:範圍掃描;
index:索引樹掃描;
ALL:全表掃描(full table scan);
上面各類掃描方式由快到慢: system > const > eq_ref > ref > range > index > ALL
我們現在來看一下爲什麼會索引失效,界面之前查詢選擇按鈕還有行政區劃一說,現在取消了行政區劃,查得最多的一項,就是按照STATUS進行查詢,這就能解釋得通爲什麼數據量變多以後,查詢就越來越慢了:
所以,根據最左原則,我們需要重新優化聯合索引,我們可以先刪除索引,在創建正確索引,刪除索引:
刪除索引可以使用ALTER TABLE或DROP INDEX語句來實現,DROP INDEX可以在ALTER TABLE內部作爲一條語句處理,其格式如下:
drop index index_name on table_name
alter table table_name drop index index_name
alter table table_name drop primary key
其中,在前面的兩條語句中,都刪除了table_name中的索引index_name。
最後一條語句只在刪除PRIMARY KEY索引中使用,因爲一個表只可能有一個PRIMARY KEY索引,因此不需要指定索引名。如果沒有創建PRIMARY KEY索引,但表具有一個或多個UNIQUE索引,則MySQL將刪除第一個UNIQUE索引
如果從表中刪除某列,則索引會受影響。對於多列組合的索引,如果刪除其中的某列,則該列也會從索引中刪除。如果刪除組成索引的所有列,則整個索引將被刪除。
刪除索引以後,我們重新創建索引:
1)使用ALTER TABLE語句創建索引
alter table table_name add index index_name (column_list) //普通索引
alter table table_name add unique (column_list) //UNIQUE索引
alter table table_name add primary key (column_list) //PRIMARY KEY索引
2)使用CREATE INDEX語句對錶增加索引
能夠增加普通索引和UNIQUE索引兩種。其格式如下:
create index index_name on table_name (column_list) ;
create unique index index_name on table_name (column_list) ;
說明:不能用CREATE INDEX語句創建PRIMARY KEY索引。
在該項目案例中,我們需要用到的語句如下:
SHOW INDEX FROM T_ECFN_PAY_LIST
EXPLAIN SELECT * FROM T_ECFN_PAY_LIST WHERE STATUS='0'
ALTER TABLE T_ECFN_PAY_LIST DROP INDEX T_ECFN_PAY_LIST_COMM_1 //刪除索引
CREATE INDEX INDEX_NAME ON T_ECFN_PAY_LIST (ADM_DIV_CODE,PAY_LIST_ID,STATUS,VOUCHER_BILL_NO,VOUCHER_NO,PAY_AMT,PAYEE_ACCT_NO) //新創建索引
SELECT * FROM T_ECFN_PAY_LIST WHERE STATUS='0' //驗證查詢效率
注:爲什麼選擇ADM_DIV_CODE和PAY_LIST_ID在前,是因爲該二者確定唯一,而界面上不能輸入該二者,所以無論什麼時候用STATUS進行查詢,都不會導致索引失效。