組合索引(concatenated index):由多個(gè)列構成的索引,如create index idx_emp on emp(col1, col2, col3, ……),則我們稱(chēng)idx_emp索引為組合索引。
在組合索引中有一個(gè)重要的概念:引導列(leading column),在上面的例子中,col1列為引導列。當我們進(jìn)行查詢(xún)時(shí)可以使用”where col1 = ? ”,也可以使用”where col1 = ? and col2 = ?”,這樣的限制條件都會(huì )使用索引,但是”where col2 = ? ”查詢(xún)就不會(huì )使用該索引。所以限制條件中包含先導列時(shí),該限制條件才會(huì )使用該組合索引。
創(chuàng )建2張測試表:

mysql> desc test1;+-------+--------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------+--------------+------+-----+---------+-------+| id | int(11) | NO | | NULL | || name | varchar(45) | YES | MUL | NULL | || dept | varchar(50) | YES | | NULL | || desc | varchar(100) | YES | | NULL | |+-------+--------------+------+-----+---------+-------+4 rows in set (0.00 sec)mysql> desc test2;+---------+-------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+---------+-------------+------+-----+---------+-------+| id | int(11) | NO | PRI | NULL | || email | varchar(50) | YES | | NULL | || address | varchar(50) | YES | | NULL | |+---------+-------------+------+-----+---------+-------+3 rows in set (0.00 sec)mysql>

通過(guò)存儲過(guò)程模擬一些數據:

delimiter $$create procedure mock_insert_test1()BEGIN DECLARE v int DEFAULT 1; WHILE v < 800000 DO INSERT into test1 VALUES(v,CONCAT('name',v),CONCAT('dept',v),NULL); SET v = v + 1; END WHILE;end$$delimiter ;delimiter $$create procedure mock_insert_test2()BEGINDECLARE v int DEFAULT 1;WHILE v < 800000DOINSERT into test2VALUES(v,CONCAT('email',v),CONCAT('addr',v));SET v = v + 1;END WHILE;end$$delimiter ;

執行存儲過(guò)程灌一些數據,

mysql> SELECT * from test1 limit 10;+----+----------+-------+------+| id | name | dept | desc |+----+----------+-------+------+| 1 | duan | yanfa | NULL || 2 | zhangsan | renli | NULL || 3 | lisi | renli | NULL || 1 | name1 | dept1 | NULL || 2 | name2 | dept2 | NULL || 3 | name3 | dept3 | NULL || 4 | name4 | dept4 | NULL || 5 | name5 | dept5 | NULL || 6 | name6 | dept6 | NULL || 7 | name7 | dept7 | NULL |+----+----------+-------+------+10 rows in set (0.00 sec)mysql>

引導列是id時(shí),索引是這樣的:inx_id_name:id,name
創(chuàng )建索引后,

結果:

引導列是name時(shí),索引是這樣的:

結果:

為什么要以name為引導列?因為ID是join列,并且ID列上面沒(méi)過(guò)濾條件,如果以ID列作為引導列,由于沒(méi)過(guò)濾條件那么CBO只能走 index full scan,或者index fast full scan,因為引導列沒(méi)過(guò)濾條件,走不了index range scan, 最多走index skip scan,不過(guò)index skip scan代價(jià)過(guò)高,因為index skip scan要求 引導列選擇性很低,但是ID這里選擇性很高。
如果name列作為引導列,那么優(yōu)化器就可以選擇index range scan,這樣相比index full scan, index fast full scan肯定要少掃描很多leaf block,邏輯讀就會(huì )相對較少。
聯(lián)系客服