聯合索引失效(未注意最左原則)問題解決

生產上有一個運行了個多月的項目,隨着數據越來越多,查詢就變得越來越慢,按理說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進行查詢,都不會導致索引失效。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章