1. 程式人生 > >MySQL索引的建立與使用

MySQL索引的建立與使用

索引有很多,且按不同的分類方式,又有很多種分類。不同的資料庫,對索引的支援情況也不盡相同。

宣告:本人主要簡單示例MySQL中的單列索引組合索引的建立與使用

索引的建立

建表時建立

CREATE TABLE 表名(

欄位名 資料型別 [完整性約束條件],

       ……,

[UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY

[索引名](欄位名1 [(長度)] [ASC | DESC]) [USING 索引方法]

);

說明:

  • UNIQUE:可選。表示索引為唯一性索引。
  • FULLTEXT:可選。表示索引為全文索引。
  • SPATIAL:可選。表示索引為空間索引。
  • INDEX和KEY:用於指定欄位為索引,兩者選擇其中之一就可以了,作用是    一樣的。
  • 索引名:可選。給建立的索引取一個新名稱。
  • 欄位名1:指定索引對應的欄位的名稱,該欄位必須是前面定義好的欄位。
  • 長度:可選。指索引的長度,必須是字串型別才可以使用。
  • ASC:可選。表示升序排列。
  • DESC:可選。表示降序排列。

注:索引方法預設使用BTREE。

單列索引(示例):

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;

檢視SQL語句對索引的使用情況(即:查詢SQL的效能)

在select語句前加上EXPLAIN即可。

示例

EXPLAIN SELECT * FROM `index_demo` ii WHERE ii.e_name = 'Jane';

分析該SQL的效能為:

提示:我們也可以使用SQL工具檢視,如:navicat中的“解釋”選項即可檢視。

說明:

id:SELECT識別符。這是SELECT的查詢序列號。

select_type:SELECT型別。

  1. SIMPLE: 簡單SELECT(不使用UNION或子查詢)
  2. PRIMARY: 最外面的SELECT
  3. UNION:UNION中的第二個或後面的SELECT語句
  4. DEPENDENT UNION:UNION中的第二個或後面的SELECT語句,取決於外面的查詢
  5. UNION RESULT:UNION的結果
  6. SUBQUERY:子查詢中的第一個SELECT
  7. DEPENDENT SUBQUERY:子查詢中的第一個SELECT,取決於外面的查詢
  8. DERIVED:匯出表的SELECT(FROM子句的子查詢)

table:表名

type:聯接型別

  1. system:表僅有一行(=系統表)。這是const聯接型別的一個特例。
  2. const:表最多有一個匹配行,它將在查詢開始時被讀取。因為僅有一行,在這行的列值可被優化器剩餘部分認為是常數。const用於用常數值比較PRIMARY KEY或UNIQUE索引的所有部分時。
  3. eq_ref:對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接型別,除了const型別。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY。eq_ref可以用於使用= 操作符比較的帶索引的列。比較值可以為常量或一個使用在該表前面所讀取的表的列的表示式。
  4. ref:對於每個來自於前面的表的行組合,所有有匹配索引值的行將從這張表中讀取。如果聯接只使用鍵的最左邊的字首,或如果鍵不是UNIQUE或PRIMARY KEY(換句話說,如果聯接不能基於關鍵字選擇單個行的話),則使用ref。如果使用的鍵僅僅匹配少量行,該聯接型別是不錯的。ref可以用於使用=或<=>操作符的帶索引的列。
  5. ref_or_null:該聯接型別如同ref,但是添加了MySQL可以專門搜尋包含NULL值的行。在解決子查詢中經常使用該聯接型別的優化。
  6. index_merge:該聯接型別表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
  7. unique_subquery:該型別替換了下面形式的IN子查詢的ref:value IN (SELECT primary_key FROMsingle_table WHERE some_expr);unique_subquery是一個索引查詢函式,可以完全替換子查詢,效率更高。
  8. index_subquery:該聯接型別類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引:value IN (SELECT key_column FROM single_table WHERE some_expr)
  9. range:只檢索給定範圍的行,使用一個索引來選擇行。key列顯示使用了哪個索引。key_len包含所使用索引的最長關鍵元素。在該型別中ref列為NULL。當使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比較關鍵字列時,可以使用range
  10. index:該聯接型別與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引檔案通常比資料檔案小。
  11. all:對於每個來自於先前的表的行組合,進行完整的表掃描。如果表是第一個沒標記const的表,這通常不好,並且通常在它情況下很差。通常可以增加更多的索引而不要使用ALL,使得行能基於前面的表中的常數值或列值被檢索出。

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解決查詢的詳細資訊。

  1. Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜尋更多的行。
  2. Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢查更多的行。
  3. range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。對前面的表的每個行組合,MySQL檢查是否可以使用range或index_merge訪問方法來索取行。
  4. Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。通過根據聯接型別瀏覽所有行併為所有匹配WHERE子句的行儲存排序關鍵字和行的指標來完成排序。然後關鍵字被排序,並按排序順序檢索行。
  5. Using index:從只使用索引樹中的資訊而不需要進一步搜尋讀取實際的行來檢索表中的列資訊。當查詢只使用作為單一索引一部分的列時,可以使用該策略。
  6. Using temporary:為了解決查詢,MySQL需要建立一個臨時表來容納結果。典型情況如查詢包含可以按不同情況列出列的GROUP BY和ORDER BY子句時。
  7. Using where:WHERE子句用於限制哪一個行匹配下一個表或傳送到客戶。除非你專門從表中索取或檢查所有行,如果Extra值不為Using where並且表聯接型別為ALL或index,查詢可能會有一些錯誤。
  8. Using sort_union(...), Using union(...), Using intersect(...):這些函式說明如何為index_merge聯接型別合併索引掃描。
  9. Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜尋硬碟訪問實際的表。並且,按最有效的方式使用索引,以便對於每個組,只讀取少量索引條目。

單列索引的使用

準備工作

給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中對應有:aa,ba,b,c的時候,可稱為完全滿足最左原則;當SQL中對應只有a,c的時候,可稱為部分滿足最左原則;當SQL中沒有a的時候,可稱為不滿足最左原則。

注:SQL語句中的對應條件的先後順序無關。

準備工作

建立了組合索引:e_name,e_age,e_country,e_city

使用情況

完全滿足最左原則

注:與條件的先後無關,即:下面這樣的話,也是會完整的走組合索引的:

部分滿足最左原則

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

不滿足最左原則

滿足(部分滿足)最左原則的欄位裡,有欄位不滿足“索引”自身的使用規範

說明:如果SQL語句裡的欄位裡,滿足了最左原則,但是不滿足“索引”自身的使用規範,那麼組合索引走到這裡之後,不會再往下走了。

如圖所示:由於e_age欄位使用了“>”符號,不符合“索引”自身的使用規範,那麼當“e_name”走完組合索引後,走到“e_age”時,該欄位及其後面的欄位不會再走組合索引了。

提示:對索引欄位進行>, <, >=, <=, not in,between …… and ……函式(索引欄位)like模糊查詢%在欄位前時不符合索引使用規範。

提示:不會使用索引的情況不全對,這個需要按照不同的情景來判斷!

微笑參考連結

微笑如涉及侵權問題,請及時聯絡我

微笑如有不當之處,歡迎指正

微笑本文已經被收錄進《程式設計師成長筆記(二)》,筆者JustryDeng