【詳細解析】MySQL索引詳解( 索引概念、6大索引類型、key 和 index 的區別、其他索引方式)
MySQL索引的概念:
- 索引是一種特殊的文件(InnoDB數據表上的索引是表空間的一個組成部分),它們包含着對數據表里所有記錄的引用指針。更通俗的說,數據庫索引好比是一本書前面的目錄,能加快數據庫的查詢速度。
- 索引分為:聚簇索引、非聚簇索引。聚簇索引是按照數據存放的物理位置為順序的,而非聚簇索引就不一樣了;聚簇索引:能提高多行檢索的速度,非聚簇索引:單行的檢索很快。
- 要注意的是,建立太多的索引將會影響更新和插入的速度,因為它需要同樣更新每個索引文件。對於一個經常需要更新和插入的表格,就沒有必要為一個很少使用的where字句單獨建立索引了,對於比較小的表,排序的開銷不會很大,也沒有必要建立另外的索引。
索引類型:
- 普通索引
- 唯一性索引
- 全文索引
- 單列索引
- 多列索引
- 空間索引


2. ‘ 直接創建索引 ’ 的基本語法結構:

3. ‘ 修改表結構的方式添加索引 ’ 的基本語法結構:

刪除索引:

索引屬性名的含義:
- UNIQUE:(unique),可選參數,表示索引為唯一索引。
- FULLTEXT:(fulltext) ,可選參數,表示索引為全文索引。
- SPATIAL:(spatial) ,可選參數,表示索引為空間索引。
- INDEX | KEY:(index | key), 必選參數,用於指定字段為索引的,用戶在選擇時,只需要二選一即可。
- [索引名]:可選參數,其作用是給創建的索引取新名稱。(起到方便使用的目的)
- 被選定的字段名:必選參數,被用作索引的對應的字段名稱,該字段必須被預先定義。
- 長度:可選參數,其指索引的長度,必須是字符串類型才可以使用。(比如:電話號碼)
- [ASC | DESC]:(asc | desc),可選參數,ASC 表示升序排列,DESC 表示降序排列。
一、普通索引 創建
創建普通索引,不需要添加 [UNIQUE | FULLTEXT | SPATIAL ] 等任何參數進行約束。
- 普通索引 (由關鍵字KEY或INDEX定義的索引) 的唯一任務是加快對數據的訪問速度。
- 只為那些最經常出現在‘查詢條件’(WHERE column = ...) 或‘排序條件’(ORDER BY column)中的數據列,來創建索引。
- 只要有可能,就應該選擇一個數據最整齊、最緊湊的數據列(如一個int整數類型的數據列)來創建索引。
例:創建的表名為 score 的數據表,並在該表的 id 字段上建立名稱為 score_id 的 ' 普通索引 ',SQL語句如下:

實例詳解:

score表的結構:

可以看出,id 字段上已經創建了一個名稱為 score_id 的索引。
score表中id=1的數據的整個執行計划:
possible_keys 和 key 的值都為
score_id,說明
score_id 索引已經存在,並且已經開始被使用了。
注意:若設定了主鍵 primary key

score表的結構:

可以看出,id 字段上已經創建了一個名稱為 score_id 的索引和 PRIMARY 的主鍵。
score表中id=1的數據的整個執行計划:
說明
score_id
索引已經存在,但已經開始被使用的是
PRIMARY 的主鍵。
二、唯一索引 創建
創建唯一索引時,使用 UNIQUE 參數對 INDEX | KEY 進行約束。
- 與普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值(注意和主鍵不同)。如果是組合索引,則列值的組合必須唯一,創建方法和普通索引類似。
- 如果能確定某個數據列將只包含彼此各不相同的值,在為這個數據列創建索引的時候就應該用關鍵字UNIQUE把它定義為一個唯一索引。這么做的好處:一是簡化了MySQL對這個索引的管理工作,這個索引也因此而變得更有效率;二是MySQL會在有新記錄插入數據表時,自動檢查新記錄的這個字段的值是否已經在某個記錄的這個字段里出現過了;如果是,MySQL將拒絕插入那條新記錄。也就是說,唯一索引可以保證數據記錄的唯一性。
- 事實上,在許多場合,人們創建唯一索引的目的往往不是為了提高訪問速度,而只是為了避免數據出現重復。
- 主索引:在前面已經反復多次強調過!必須為主鍵字段創建一個索引,這個索引就是所謂的"主索引"。
- 主索引 與 唯一索引的唯一區別是:前者在定義時使用的關鍵字是PRIMARY而不是UNIQUE。
例:創建的表名為 address 的數據表,並在該表的 id 字段上建立名稱為 address_id 的 ' 唯一索引 ',SQL語句如下:

三、全文索引 創建
全文索引只能作用在 CHAR、VARCHAR、TEXT、類型的字段上。創建全文索引需要使用 FULLTEXT 參數進行約束。
- MySQL從3.23.23版開始支持全文索引和全文檢索,fulltext索引僅可用於 MyISAM 表;他們可以從CHAR、VARCHAR或TEXT列中作為CREATE TABLE語句的一部分被創建,或是隨后使用ALTER TABLE 或CREATE INDEX被添加。
- 對於較大的數據集,將你的資料輸入一個沒有FULLTEXT索引的表中,然后創建索引,其速度比把資料輸入現有FULLTEXT索引的速度更為快。不過切記對於大容量的數據表,生成全文索引是一個非常消耗時間非常消耗硬盤空間的做法。
- 文本字段上的普通索引只能加快對出現在字段內容最前面的字符串(也就是字段內容開頭的字符)進行檢索操作。如果字段里存放的是由幾個、甚至是多個單詞構成的較大段文字,普通索引就沒什么作用了。這種檢索往往以LIKE %word%的形式出現,這對MySQL來說很復雜,如果需要處理的數據量很大,響應時間就會很長。
- 這類場合正是全文索引(full-text index)可以大顯身手的地方。在生成這種類型的索引時,MySQL將把在文本中出現的所有單詞創建為一份清單,查詢操作將根據這份清單去檢索有關的數據記錄。全文索引即可以隨數據表一同創建,也可以等日后有必要時再使用命令添加。
- 有了全文索引,就可以用SELECT查詢命令去檢索那些包含着一個或多個給定單詞的數據記錄了。下面是這類查詢命令的基本語法:
WHERE MATCH(column1, column2) AGAINST('word1', 'word2', 'word3')
- 上面這條命令將把column1和column2字段里有word1、word2和word3的數據記錄全部查詢出來。
例:創建的表名為 cards 的數據表,並在該表的 name 字段上建立名稱為 cards_number 的 ' 全文索引 ',SQL語句如下:

四、單列索引 創建
創建單列索引,即在數據表的單個字段上創建索引。創建該類型索引不需要引入約束參數,用戶在建立時只需要指定單列字段名,即可創建單列索引。
- 多個單列索引與單個多列索引的查詢效果不同,因為執行查詢時,MySQL只能使用一個索引,會從多個索引中選擇一個限制最為嚴格的索引。
例:創建的表名為 telephone 的數據表,並在該表的 tel 字段上建立名稱為 tel_num 的單列索引,SQL 語句如下:

五、多列索引 創建
創建多列索引,即在數據表的多個字段上創建索引。與上述單列索引類似,創建該類型索引不需要引入約束參數。
- 多個單列索引與單個多列索引的查詢效果不同,因為執行查詢時,MySQL只能使用一個索引,會從多個索引中選擇一個限制最為嚴格的索引。
例:創建的表名為 information 的數據表,並在該表的 name 和 sex 字段上建立名稱為 info 的多列索引,SQL 語句如下:

注意:在多列索引中,只有查詢條件中使用了這些字段中的第一個字段(即上面示例中的 name 字段),索引才會被使用。
觸發多列索引的條件是用戶必須使用索引的第一字段,如果沒有用到第一字段,則索引不起任何作用,用戶想要優化查詢速度,可以應用該類索引形式。
例:組合(復合)索引 ---(‘最左前綴’原則)
針對 title 和 time 建立一個組合索引:alter table info add index `index_title_time` (`title`(50),`time`(10))。建立這樣的組合索引,其實是相當於分別建立了下面兩組組合索引:
–title,time
–title
為什么沒有time這樣的組合索引呢?這是因為MySQL組合索引“最左前綴”的結果。簡單的理解就是只從最左面的開始組合。並不是只要包含這兩列的查詢都會用到該組合索引,如下面的幾個SQL所示:
–title,time
–title
為什么沒有time這樣的組合索引呢?這是因為MySQL組合索引“最左前綴”的結果。簡單的理解就是只從最左面的開始組合。並不是只要包含這兩列的查詢都會用到該組合索引,如下面的幾個SQL所示:
使用到上面的索引:
SELECT * FROM article WHREE title='測試' AND time=1234567890;
SELECT * FROM article WHREE title='測試';
–不使用上面的索引
SELECT * FROM article WHREE time=1234567890;
SELECT * FROM article WHREE title='測試';
–不使用上面的索引
SELECT * FROM article WHREE time=1234567890;
六、空間索引 創建
創建空間索引,需要添加 SPATIAL 參數進行約束。
同樣,必須說明的是,只有 MyISAM 類型的表支持該類型 ‘ 空間索引 ’。而且,索引字段必須有非空約束。
創建的表名為 list 的數據表,並在該表的 goods 字段上建立名稱為 listinfo 的空間索引,這里 goods 字段有非空約束,符合條件,SQL 語句如下:

注意: goods 字段上已經建立名稱為 listinfo 的空間索引,其中 goods 字段必須不能為空,且數據類型是 GEOMETRY,該類型是空間數據類型。
空間類型不能用其他類型代替,否則在生成空間素引時會產生錯誤且不能正常創建該類型索引。
**外鍵索引**:
如果為某個外鍵字段定義了一個外鍵約束條件,MySQL就會定義一個內部索引來幫助自己以最有效率的方式去管理和使用外鍵約束條件。
另外:INDEX | KEY:(index | key), 必選參數,用於指定字段為索引的,用戶在選擇時,只需要二選一即可。
具體什么時候選 INDEX ,什么時候選 KEY ?
參照兩者區別:
1). key :是數據庫的物理結構,它包含兩層意義:一是約束(偏重於約束和規范數據庫的結構完整性)、二是索引(輔助查詢用的)。包括primary key, unique key, foreign key 等。
primary key 有兩個作用,一是約束作用(constraint),用來規范一個存儲主鍵和唯一性,但同時也在此key上建立了一個index;
unique key 也有兩個作用,一是約束作用(constraint),規范數據的唯一性,但同時也在這個key上建立了一個index;
foreign key也有兩個作用,一是約束作用(constraint),規范數據的引用完整性,但同時也在這個key上建立了一個index;
2). index:是數據庫的物理結構,它包含一層意義:它只是索引(輔助查詢用的),它創建時會在另外的表空間(mysql中的innodb表空間)以一個類似目錄的結構存儲。
因此,索引只是索引,它不會去約束索引的字段的行為(那是key要做的事情)。
primary key 有兩個作用,一是約束作用(constraint),用來規范一個存儲主鍵和唯一性,但同時也在此key上建立了一個index;
unique key 也有兩個作用,一是約束作用(constraint),規范數據的唯一性,但同時也在這個key上建立了一個index;
foreign key也有兩個作用,一是約束作用(constraint),規范數據的引用完整性,但同時也在這個key上建立了一個index;
2). index:是數據庫的物理結構,它包含一層意義:它只是索引(輔助查詢用的),它創建時會在另外的表空間(mysql中的innodb表空間)以一個類似目錄的結構存儲。
因此,索引只是索引,它不會去約束索引的字段的行為(那是key要做的事情)。
3). 最后的釋疑:
1. 我們說索引分類,分為主鍵索引、唯一索引、普通索引(這才是純粹的index)等,也是基於是不是把index看作了key。
比如 create table t(id int, unique index inx_tx_id (id)); --- index當作了key使用,因為前面的 unique 賦予了 ‘約束’,使其具有和 key 一樣的作用。
2. 最重要的也就是,不管如何描述,理解index是純粹的index,還是被當作key,當作key時則會有兩種意義或起兩種作用。
1. 我們說索引分類,分為主鍵索引、唯一索引、普通索引(這才是純粹的index)等,也是基於是不是把index看作了key。
比如 create table t(id int, unique index inx_tx_id (id)); --- index當作了key使用,因為前面的 unique 賦予了 ‘約束’,使其具有和 key 一樣的作用。
2. 最重要的也就是,不管如何描述,理解index是純粹的index,還是被當作key,當作key時則會有兩種意義或起兩種作用。