記一次MySql單列索引和聯合索引的使用區別

狀況是這樣,有一張表,創建了一個組合索引,好比:userId,userType,orgId這三個字段組合,順序也是這樣的,而後寫sql的時候這樣寫的:mysql

 select * from user where userType=0 and userId=1;

 同事說這樣寫SQL的效率會有影響,創建聯合索引的時候字段是什麼順序就要按照順序來,因此要把後面的where條件改成 userId=1 and userType=0才能夠,之前還真沒有注意過,此次本身親自試驗了一下。sql

創建兩張表,其實表結構同樣,只不過表名和索引類型不同app

CREATE TABLE `gift` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵,自增',
  `name` varchar(50) DEFAULT NULL COMMENT '道具名稱',
  `description` varchar(300) DEFAULT NULL COMMENT '道具功能簡介',
  `status` tinyint(1) DEFAULT NULL COMMENT '道具狀態,1:啓用中,0:',
  `scene_type` int(11) DEFAULT NULL COMMENT '場景類型,0:直播場景,1:回放場景',
  `price` float DEFAULT NULL COMMENT '價格',
  `integration` float DEFAULT NULL COMMENT '道具積分',
  `charge_status` int(11) DEFAULT NULL COMMENT '收費狀態(0:免費,1:收費,2:折扣)',
  `rank` int(11) DEFAULT NULL COMMENT '排序,好比有新道具,須要優先進行推薦',
  `app_id` int(11) DEFAULT NULL COMMENT '應用的標識',
  `create_time` datetime DEFAULT NULL COMMENT '建立時間',
  `create_user` int(11) DEFAULT NULL COMMENT '建立人ID',
  `data` varchar(1000) DEFAULT NULL COMMENT '預留字段,用來存放logo,效果圖等信息,JSON串形式',
  PRIMARY KEY (`id`),
  KEY `idx` (`name`,`status`,`scene_type`,`app_id`)
) ENGINE=InnoDB AUTO_INCREMENT=786663 DEFAULT CHARSET=utf8;

 

第一張表gift和索引爲聯合索引,如圖:mysql索引

第二張表gift2爲單列索引,如圖:測試

 

下面開始進行測試:優化

相同的SQL分別查詢兩張表,使用EXPLAIN解析一下SQLspa

EXPLAIN select * from gift where `name`='道具' and scene_type=1;
EXPLAIN select * from gift2 where `name`='道具' and scene_type=1;

     顯示的結果爲兩條SQL都會使用到索引,這我就不上圖了。code

而後只查詢其中的某列,可是這個列已經建立索引排序

EXPLAIN select `name`,`status` from gift where `name`='道具' and scene_type=1;
EXPLAIN select `name`,`status` from gift2 where `name`='道具' and scene_type=1;

    顯示的結果爲兩條SQL也都使用了索引。索引

繼續查詢沒有建立索引的列,這裏rank字段並無建立索引

EXPLAIN select `name`,`status`,rank from gift where `name`='道具' and scene_type=1;
EXPLAIN select `name`,`status`,rank from gift2 where `name`='道具' and scene_type=1;

     顯示的結果爲兩條SQL也都使用了索引。

接下來把SQL調整一下,name字段都創建了索引,下面把where條件裏的name條件去掉

EXPLAIN select `name`,`status` from gift where scene_type=1;
EXPLAIN select `name`,`status` from gift2 where scene_type=1;

     顯示的結果爲兩條SQL也都使用了索引。

仍是上面這條SQL,把rank列再加上去,再查看下效果

EXPLAIN select `name`,`status`,rank from gift where scene_type=1;
EXPLAIN select `name`,`status`,rank from gift2 where scene_type=1;

    這個時候比較奇怪的事情就出來,第一條SQL根本沒有用到索引,第二條SQL還和之前同樣,一樣使用到了索引。

其實在聯合索引上會有一個mysql索引最左匹配原則,可是若是聯合索引的第一個列不在where條件語句中,而且所查詢的列其中有的是沒有創建索引的,那麼這個聯合索引就是無效的,具體爲何會這樣我也尚未整明白(囧),不過之後再寫SQL也會注意一下這方面的問題,並且公司DBA也建議若是使用聯合索引,那麼where條件也要儘可能根據聯合索引的順序來,若是不按照順序來,索引也一樣會用到,可是在執行前,SQL優化器也會將條件調整爲聯合索引的順序,既然能夠直接避免這種狀況,就不必再讓SQL優化器去處理,畢竟處理也是有開銷的。

相關文章
相關標籤/搜索