索引有很多,且按不同的分類方式,又有很多種分類。不同的數據庫,對索引的支持情況也不盡相同。
聲明:本人主要簡單示例mysql中的單列索引、組合索引的創建與使用。
CREATE TABLE 表名(
字段名 數據類型 [完整性約束條件],
???????……,
[UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY
[索引名](字段名1 [(長度)] [ASC | DESC]) [USING 索引方法]
);
說明:
注:索引方法默認使用B+TREE。
單列索引(示例):
CREATE TABLE projectfile ( id INT AUTO_INCREMENT COMMENT '附件id', fileuploadercode VARCHAR(128) COMMENT '附件上傳者code', projectid INT COMMENT '項目id;此列受project表中的id列約束', filename VARCHAR (512) COMMENT '附件名', fileurl VARCHAR (512) COMMENT '附件下載地址', filesize BIGINT COMMENT '附件大小,單位Byte', -- 主鍵本身也是一種索引(注:也可以在上面的創建字段時使該字段主鍵自增) PRIMARY KEY (id), -- 主外鍵約束(注:project表中的id字段約束了此表中的projectid字段) FOREIGN KEY (projectid) REFERENCES project (id), -- 給projectid字段創建了唯一索引(注:也可以在上面的創建字段時使用unique來創建唯一索引) UNIQUE INDEX (projectid), -- 給fileuploadercode字段創建普通索引 INDEX (fileuploadercode) -- 指定使用INNODB存儲引擎(該引擎支持事務)、utf8字符編碼) ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT '項目附件表'; 注:這里只為示例如何創建索引,其他的合理性之類的先放一邊。
組合索引(示例):
CREATE TABLE projectfile ( id INT AUTO_INCREMENT COMMENT '附件id', fileuploadercode VARCHAR(128) COMMENT '附件上傳者code', projectid INT COMMENT '項目id;此列受project表中的id列約束', filename VARCHAR (512) COMMENT '附件名', fileurl VARCHAR (512) COMMENT '附件下載地址', filesize BIGINT COMMENT '附件大小,單位Byte', -- 主鍵本身也是一種索引(注:也可以在上面的創建字段時使該字段主鍵自增) PRIMARY KEY (id), -- 創建組合索引 INDEX (fileuploadercode,projectid) -- 指定使用INNODB存儲引擎(該引擎支持事務)、utf8字符編碼) ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT '項目附件表'; ALTER?TABLE?表名?ADD?[UNIQUE | FULLTEXT | SPATIAL]??INDEX | KEY??[索引名]?(字段名1 [(長度)] [ASC | DESC])?[USING 索引方法];
或
CREATE??[UNIQUE | FULLTEXT | SPATIAL]??INDEX??索引名?ON??表名(字段名)?[USING 索引方法];
示例一:
-- 假設建表時fileuploadercode字段沒創建索引(注:同一個字段可以創建多個索引,但一般情況下意義不大)-- 給projectfile表中的fileuploadercode創建索引ALTER TABLE projectfile ADD UNIQUE INDEX (fileuploadercode); 示例二:
ALTER TABLE projectfile ADD INDEX (fileuploadercode, projectid); 示例三:
-- 將id列設置為主鍵ALTER TABLE index_demo ADD PRIMARY KEY(id) ;-- 將id列設置為自增ALTER TABLE index_demo MODIFY id INT auto_increment; show index from 表名;
提示:我們也可以直接使用工具查看
示例:

DROP INDEX 索引名 ON 表名
或
ALTER TABLE 表名 DROP INDEX?索引名
示例一:
drop index fileuploadercode1 on projectfile; 示例二:
alter table projectfile drop index s2123; 在select語句前加上EXPLAIN即可。
示例:
EXPLAIN SELECT * FROM `index_demo` ii WHERE ii.e_name = 'Jane'; 分析該SQL的性能為:

提示:我們也可以使用SQL工具查看,如:navicat中的“解釋”選項即可查看。
說明:
id:SELECT識別符。這是SELECT的查詢序列號。
select_type:SELECT類型。
table:表名
type:聯接類型。是SQL性能的非常重要的一個指標,結果值從好到壞依次是:system > const > eq_ref > ref
? ? ? ? ? ??> fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL。
? ? ? ? ? ??一般來說,得保證查詢至少達到range級別。
possible_keys:possible_keys列指出MySQL能使用哪個索引在該表中找到行。注意,該列完全獨立于EXPLAIN輸出所示的表的次序。這意味著在possible_keys中的某些鍵實際上不能按生成的表次序使用。
key:key列顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。要想強制MySQL使用或忽視possible_keys列中的索引,在查詢中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
key_len:key_len列顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。注意通過key_len值我們可以確定MySQL將實際使用一個多部關鍵字的幾個部分。
ref:ref列顯示使用哪個列或常數與key一起從表中選擇行。
rows:rows列顯示MySQL認為它執行查詢時必須檢查的行數。
Extra:該列包含MySQL解決查詢的詳細信息。
給id加主鍵索引:

再分別給name、city、country、address加上普通索引:

注:以上五個索引都是單列索引。
只涉及到其中的一個字段時,都能使用到索引(以e_name為例):


注:模糊查詢時,%如果在前面,那么不會使用索引。
涉及到多個索引字段時,如果這些索引字段中,存在主鍵索引,那么只會使用該索引(即:MYSQL優化器會選出并先執行最“嚴”的索引):

提示:possible_key中,只是SQL語句里涉及到的索引;key中才是實際上執行查詢操作時使用到了的索引。
涉及到多個索引字段時,如果這些索引字段中,不存在主鍵索引的話,那么就會使用該使用的索引(注:如果通過其中的部分索引就能準確定位的話,那么其余的索引就不再被使用):


注:多個索引時,先使用哪個索引后使用哪個索引,是由MySQL的優化器經過一些列計算后作出的抉擇。
當對索引字段進行?>,?<,>=, <=,not in,between …… and ……,函數(索引字段),like模糊查詢%在字段前時,不會使用該索引

注:這里對e_age字段進行了 “<” ,所以實際查詢時,并沒有使用e_age的索引。
提示:在實際使用時,如果涉及到多列,我們一般都不會將這些列一 一創建為單列索引,而是將這些列創建為組合索引。
? ? ? ?假設組合索引為:a,b,c的話;那么當SQL中對應有:a或a,b或a,b,c的時候,可稱為完全滿足最左原則;當SQL中查詢條件對應只有a,c的時候,可稱為部分滿足最左原則;當SQL中沒有a的時候,可稱為不滿足最左原則。
注:MySQL5.7開始,會自動優化,如:會把c,b,a優化為a,b,c使之完全遵循最左原則;會把c,a優化為a,c使之部
? ? ? ?分遵循最左原則。即:SQL語句中的對應條件的先后順序無關。

創建了組合索引:e_name,e_age,e_country,e_city。
完全滿足最左原則:

注:與條件的先后無關(這是因為MYSQL5.7開始,對索引全排列有優化,會自動優化為按組合索引的順序進行查詢),
? ? ? ?即:下面這樣的話,也是會完整的走組合索引的:

部分滿足最左原則:

注:此SQL中,只有e_name和e_country滿足部分最左原則(e_name滿足),所以到e_name字段時會走組合所以,但是
? ? ? ?只會走到e_name那里,到e_country時就不會使用組合索引了。
不滿足最左原則:

滿足(部分滿足)最左原則的字段里,有字段不滿足“索引”自身的使用規范:
說明:如果SQL語句里的字段里,滿足了最左原則,但是不滿足“索引”自身的使用規范,那么組合索引走到這里之后,
? ? ? ? ? ?不會再往下走了。

如圖所示:由于e_age字段使用了“>”符號,不符合“索引”自身的使用規范,那么當“e_name”走完組合索引后,
? ? ? ? ? ? ? ? ??走到“e_age”時,該字段及其后面的字段不會再走組合索引了。
聚集索引與非聚集索引:
? ? ? ?每個InnoDB表具有一個特殊的索引稱為聚簇索引(也叫聚集索引,聚類索引,簇集索引)。如果表上定義有主鍵,該主鍵索引就是聚簇索引。如果未定義主鍵,MySQL取第一個唯一索引(unique)而且只含非空列(NOT NULL)作為主鍵,InnoDB使用它作為聚簇索引。如果沒有這樣的列,InnoDB就自己產生一個這樣的ID值,它有六個字節,而且是隱藏的,使其作為聚簇索引。
? ? ? ?表中的聚簇索引(clustered index )就是一級索引,除此之外,表上的其他非聚簇索引都是二級索引,又叫輔助索引(secondary indexes)。
回表:
? ? ? ? 當二級索引無法直接查詢到(SQL中select需要的所有)列的數據時,會通過二級索引查詢到聚簇索引(即:一級索引)后,再根據(聚集索引)查詢到(二級索引中無法提供)的數據,這種通過二級索引查詢出一級索引,再通過一級索引查詢(二級索引中無法提供的)數據的過程,就叫做回表。
如,現有表:

id是主鍵,其余三個字段組成聯合索引:

當不需要進行回表時,即便我們的SQL不滿足組合索引最左原則,也會走組合索引的,如:

? ? ? ? 這里where后直接是gender時, 是不遵循組合索引的最左原則的,但是查詢計劃顯示使用了索引的。這是因為: 對這張表進行select *,相當于進行select id,name,age,gender,其中,id是主鍵(一級索引),name、age、gender是組合索引(二級索引),這里查詢時,能直接從索引中拿到想要查詢的所有列的數據,是不需要回表查詢的,所以這里哪怕sql寫法上不遵循最左原則,但是仍然是會走索引的。
如果這個時候,我們加一個普通的motto字段:

?
使用相同的SQL進行查詢,可看到:

?
? ? ? ? 此時進行select *,相當于進行select id,name,age,gender,motto,其中motto字段是從索引(一級索引、二級索引)里面獲取不到數據的,是肯定需要回表的。而查詢條件又不遵循最左原則,所以不會走組合索引。
注:其它情況下,只有(完全或部分)遵循了最左原則,才會走組合索引。
新聞熱點
疑難解答