一、什么是索引?
索引用來快速地尋找那些具有特定值的記錄,所有MySQL索引都以B-樹的形式保存。如果沒有索引,執行查詢時MySQL必須從第一個記錄開始掃描整個表的所有記錄,直至找到符合要求的記錄。表里面的記錄數量越多,這個操作的代價就越高。如果作為搜索條件的列上已經創建了索引,MySQL無需掃描任何記錄即可迅速得到目標記錄所在的位置。如果表有1000個記錄,通過索引查找記錄至少要比順序掃描記錄快100倍。
二、索引的類型
MySQL提供多種索引類型供選擇:
普通索引
這是最基本的索引類型,而且它沒有唯一性之類的限制。普通索引可以通過以下幾種方式創建:
創建索引,例如CREATE INDEX <索引的名字> ON tablename (列的列表);
修改表,例如ALTER TABLE tablename ADD INDEX [索引的名字] (列的列表);
創建表的時候指定索引,例如CREATE TABLE tablename ( [...], INDEX [索引的名字] (列的列表) );
唯一性索引
這種索引和前面的“普通索引”基本相同,但有一個區別:索引列的所有值都只能出現一次,即必須唯一。唯一性索引可以用以下幾種方式創建:
創建索引,例如CREATE UNIQUE INDEX <索引的名字> ON tablename (列的列表);
修改表,例如ALTER TABLE tablename ADD UNIQUE [索引的名字] (列的列表);
創建表的時候指定索引,例如CREATE TABLE tablename ( [...], UNIQUE [索引的名字] (列的列表) );
主鍵
主鍵是一種唯一性索引,但它必須指定為“PRIMARY KEY”。如果你曾經用過AUTO_INCREMENT類型的列,你可能已經熟悉主鍵之類的概念了。主鍵一般在創建表的時候指定,例如“CREATE TABLE tablename ( [...], PRIMARY KEY (列的列表) ); ”。但是,我們也可以通過修改表的方式加入主鍵,例如“ALTER TABLE tablename ADD PRIMARY KEY (列的列表); ”。每個表只能有一個主鍵。
全文索引
MySQL從3.23.23版開始支持全文索引和全文檢索。在MySQL中,全文索引的索引類型為FULLTEXT。全文索引可以在VARCHAR或者TEXT類型的列上創建。它可以通過CREATE TABLE命令創建,也可以通過ALTER TABLE或CREATE INDEX命令創建。對於大規模的數據集,通過ALTER TABLE(或者CREATE INDEX)命令創建全文索引要比把記錄插入帶有全文索引的空表更快。本文下面的討論不再涉及全文索引,要了解更多信息,請參見MySQL documentation。
索引的缺點
到目前為止,我們討論的都是索引的優點。事實上,索引也是有缺點的。
首先,索引要占用磁盤空間。通常情況下,這個問題不是很突出。但是,如果你創建每一種可能列組合的索引,索引文件體積的增長速度將遠遠超過數據文件。如果你有一個很大的表,索引文件的大小可能達到操作系統允許的最大文件限制。
第二,對於需要寫入數據的操作,比如DELETE、UPDATE以及INSERT操作,索引會降低它們的速度。這是因為MySQL不僅要把改動數據寫入數據文件,而且它還要把這些改動寫入索引文件。
索引與主鍵的主要區別有:
主鍵是一種約束,唯一索引是一種索引,兩者在本質上是不同的。
主鍵創建后一定包含一個唯一性索引,唯一性索引並不一定就是主鍵。
唯一性索引列允許空值,而主鍵列不允許為空值。
主鍵列在創建時,已經默認為空值 + 唯一索引了。
主鍵可以被其他表引用為外鍵,而唯一索引不能。
一個表最多只能創建一個主鍵,但可以創建多個唯一索引。
主鍵更適合那些不容易更改的唯一標識,如自動遞增列、身份證號等。
在 RBO 模式下,主鍵的執行計划優先級要高於唯一索引。 兩者可以提高查詢的速度。
-- 創建一張僅包含主鍵和唯一索引的表
CREATE TABLE test
(PrimaryKey VARCHAR2(20),
UniqueKey VARCHAR2(20)
);
-- 分別創建主鍵和唯一索引,語法不同
ALTER TABLE test ADD CONSTRAINT test_PrimaryKey PRIMARY KEY (PrimaryKey);
CREATE UNIQUE INDEX test_UniqueKey ON test (UniqueKey);
-- 在 USER_INDEXES 中可以看到兩個索引名稱
SELECT table_name,table_type,index_name,index_type,uniqueness
FROM USER_INDEXES
WHERE TABLE_NAME='TEST';
-- 在 USER_IND_COLUMNS 中可以看到兩個索引字段名稱
SELECT table_name,index_name,column_name,column_position
FROM USER_IND_COLUMNS
WHERE TABLE_NAME='TEST';
-- 在 USER_CONSTRAINTS 僅可以看到主鍵約束名稱
SELECT table_name,constraint_name,constraint_type
FROM USER_CONSTRAINTS
WHERE TABLE_NAME='TEST';
-- 在 USER_CONS_COLUMNS 僅可以看到主鍵約束字段名稱
SELECT table_name,constraint_name,column_name,position
FROM USER_CONS_COLUMNS
WHERE CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME
FROM USER_CONSTRAINTS
WHERE TABLE_NAME='TEST');
-- 為唯一索引增加一個非空約束
ALTER TABLE test MODIFY UniqueKey NOT NULL;
-- 在 USER_CONSTRAINTS 僅可以看到主鍵約束名稱和非空約束名稱
SELECT table_name,constraint_name,constraint_type
FROM USER_CONSTRAINTS
WHERE TABLE_NAME='TEST'
-- 在 USER_CONS_COLUMNS 僅可以看到主鍵約束字段名稱和非空約束字段名稱
SELECT table_name,constraint_name,column_name,position
FROM USER_CONS_COLUMNS
WHERE CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME
FROM USER_CONSTRAINTS
WHERE TABLE_NAME='TEST')