MySql(三) 多個單列索引與聯合索引的區別

探究問題:爲了提高查詢效率,添加索引很常見,但是建立多個單列索引聯合索引有何區別呢?

準備工作

  • 數據庫:MySql 5.7.11-log
  • 創建表
create table temp_index_test(
    indexId int,
    indexName varchar(10),
    indexValue int,
    is_del int
  );
  • 插入數據
insert temp_index_test value (1,'索引1',1,0);
insert temp_index_test value (2,'索引2',2,0);
insert temp_index_test value (3,'索引3',3,0);
insert temp_index_test value (4,'索引4',4,0);
insert temp_index_test value (5,'索引5',5,0);
  • 查詢數據插入情況


 

聯合索引驗證 

添加聯合索引 indexId_indexName

  • 只使用indexId,查看執行計劃
    explain
      select *
      from temp_index_test where indexId='1';

索引生效! 

  • 只使用indexName,查看執行計劃
explain
  select *
  from temp_index_test where indexName='索引1';

  索引未生效!   

  •  同時使用indexId,indexName,並且indexId在前,indexName在後
explain
  select *
  from temp_index_test where indexId=1 and indexName='索引1';

索引生效! 

  •  同時使用indexId,indexName,並且indexName在前,indexId在後
explain
  select *
  from temp_index_test where indexName='索引1' and indexId=1;

 索引生效!

中間添加一個沒有添加索引的字段


explain
  select *
  from temp_index_test where indexId=1 and indexValue=1 and indexName='索引1';

 索引生效!

總結:

  • 利用索引中的附加列,您可以縮小搜索的範圍,但使用一個具有兩列的索引不同於使用兩個單獨的索引。複合索引的結構與電話簿類似,人名由姓和名構成,電話簿首先按姓氏對進行排序,然後按名字對有相同姓氏的人進行排序。如果您知道姓,電話簿將非常有用;如果您知道姓和名,電話簿則更爲有用,但如果您只知道名不姓,電話簿將沒有用處。
  • 所以說創建複合索引時,應該仔細考慮列的順序。對索引中的所有列執行搜索或僅對前幾列執行搜索時,複合索引非常有用僅對後面的任意列執行搜索時,複合索引則沒有用處。
  • 如何建立聯合索引順序?最左前綴原則,可以理解爲在複合索引中,越是左邊越好
    因爲分別對A,B,C三個列建聯合索引index,實際上是建立3個索引,每個索引都包含A,組合分別爲【A|A,B,C|A,B】
    AC組合也可以,只不過只用到了A的索引,C的沒有用到!

【注意】

     最左前綴原則

  • 如果第一個字段是範圍查詢需要單獨建一個索引
  • 在創建聯合索引時,要根據業務需求,where子句中使用最頻繁的一列放在最左邊。這樣的話擴展性較好
  • 【列基數】,是指它所容納的所有非重複值的個數,可以理解爲 distinct(某列)後的結果,比如某個列包含值1,3,7,4,7,3,那麼它的基數就是4了,列基數越大,重複值越少,需要建索引,因爲如果某列的值都是重複的就沒必要建索引了是(`DistriType`,`DistriButTime`) 這樣建?還是這樣建 (`DistriButTime`,`DistriType`) ?
    count(distinct DistriType) 與 count(distinct DistriButTime)比較猜測肯定是前者>後者,所以聯合索引把DistriTyp放左邊更優

多個單列索引驗證

添加單列索引indexId,indexName

  • 使用indexId查詢
explain
  select *
  from temp_index_test where indexid=1;

索引生效! 

  •  使用IndexId,indexName查詢
explain
  select *
  from temp_index_test where indexid=1 and indexName='索引1';

只使用了index索引! 

爲什麼沒有用上indexName索引

那麼爲什麼沒有用上呢?按照我們的理解,2個字段都加索引了,無論怎麼排列組合查詢,應該都能利用到這2個索引纔對!

其實這裏其實涉及到了mysql優化器的優化策略!當多條件聯合查詢時,優化器會評估用哪個條件的索引效率最高!它會選擇最佳的索引去使用,也就是說,此處indexIdindexName這三個索引列都能用,只不過優化器判斷只需要使用indexId這一個索引就能完成本次查詢,故最終explain展示的key爲indexId

當然,如果優化器判斷本次查詢非要全使用三個索引才能效率最高,那麼explain的key就會是indexIdindexName,都會生效!

【是不是跟索引的先後順序有關呢】

將indexId與indexName調換位置,測試一下

#兩個索引都使用
explain
  select indexName
  from temp_index_test where indexName='索引1' and indexId = 1 and is_del=0;

 依舊使用的索引爲indexId,所以跟順序無關!

  • 將索引條件連接由AND換成OR
explain
  select indexName
  from temp_index_test where indexName='索引1' or  indexId = 1;

沒有使用索引! 


涉及到的其他點:

  • 需要加索引的字段,要在where條件中
  • 數據量少的字段不需要加索引;因爲建索引有一定開銷,如果數據量小則沒必要建索引(速度反而慢)
  • 避免在where子句中使用or來連接條件,因爲如果倆個字段中有一個沒有索引的話,引擎會放棄索引而產生全表掃描
  • 聯合索引比對每個列分別建索引更有優勢,因爲索引建立得越多就越佔磁盤空間,在更新數據的時候速度會更慢。另外建立多列索引時,順序也是需要注意的,應該將嚴格的索引放在前面,這樣篩選的力度會更大,效率更高
  • 有人說where查詢是按照從左到右的順序,所以篩選力度大的條件儘量放前面。網上百度過,很多都是這種說法,但是據我研究,mysql執行優化器會對其進行優化當不考慮索引時,where條件順序對效率沒有影響真正有影響的是是否用到了索引但是推薦按照篩選力度大的排前面,mysql優化器優化也會耗費性能!
  • 同時存在聯合索引和單列索引(字段有重複的),當一個表有多條索引可走時, Mysql 根據查詢語句的成本來選擇走哪條索引

參考:

聯合索引區別詳解

MySql組合索引在使用時有順序的區別嗎

發佈了55 篇原創文章 · 獲贊 10 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章