什么是索引?為什么要建立索引?索引分類?索引的使用?轉載SQL(五) MySQL中的索引詳講
一、索引介紹:
索引用於快速找出在某個列中有一特定值的行。不使用索引,MySQL必須從第一條記錄開始讀完整個表,直到找出相關的行,表越大查詢數據所花費的時間就越多。如果表中查詢的列有索引,MySQL能夠快速到達一個位置去搜索數據文件,而不必查看所有數據,那么將會節省很大一部分時間。
例如:有一張person表,其中有2W條記錄,記錄着2W個人的信息。有一個Phone的字段記錄每個人的電話號碼,現在想要查詢出電話號碼為xxxx的人的信息。
如果沒有索引,那么將從表中第一條記錄一條條往下遍歷,直到找到該條信息為止。
如果有了索引,那么會將 Phone 字段,通過一定的方法進行存儲,好讓查詢該字段上的信息時,能夠快速找到對應的數據,而不必在遍歷2W條數據了。其中MySQL中的索引的存儲類型有兩種:BTREE、HASH。 也就是用樹或者Hash值來存儲該字段,更詳細的查找邏輯就需要會算法的知識了。我們現在只需要知道索引的作用,功能是什么就行。
二、索引優缺點:
優點:
1、所有的MySql列類型(字段類型)都可以被索引,也就是可以給任意字段設置索引。
2、大大加快數據的查詢速度。
缺點:
1、創建索引和維護索引要耗費時間,並且隨着數據量的增加所耗費的時間也會增加。
2、索引也需要占空間,我們知道數據表中的數據也會有最大上線設置的,如果我們有大量的索引,索引文件可能會比數據文件更快達到上線值。
3、當對表中的數據進行增加、刪除、修改時,索引也需要動態的維護,降低了數據的維護速度。
使用原則:
通過上面說的優點和缺點,我們應該可以知道,並不是每個字段都設置為索引好,也不是索引越多越好,而是需要自己合理的使用。
1、對經常更新的表就避免對其設置過多的索引,對經常用於查詢的字段應該創建索引。
2、數據量小的表最好不要使用索引,因為由於數據較少,可能查詢全部數據花費的時間比遍歷索引的時間還要短,索引就可能不會產生優化效果。
3、在一個列上(字段上)不同值較少的不要建立索引,比如在學生表的"性別"字段上只有男,女兩個不同值。相反的,在一個字段上不同值較多的可是建立索引。
以上簡單的說下索引的優缺點,在以后的使用中再慢慢總結。
三、索引的分類
索引是在存儲引擎中實現的,也就是說不同的存儲引擎,會使用不同的索引:
MyISAM和InnoDB存儲引擎:只支持BTREE索引, 也就是說默認使用BTREE,不能夠更換。(但是innoDB存儲引擎支持hash索引是自適應的,innoDB存儲引擎會根據表的使用情況自動為表生成hash索引,不能人為干預是否在一張表中生成hash索引。后續再整理)
MEMORY/HEAP存儲引擎:支持HASH和BTREE索引。
存儲引擎的類型及特點:
引擎名稱 |
優點 |
缺陷 |
應用場景 |
MyISAM |
獨立於操作系統,這說明可以輕松地將其從Windows服務器移植到Linux服務器 |
不支持事務/行級鎖/外鍵約束 |
適合管理郵件或Web服務器日志數據 |
InnoDB |
健壯的事務型存儲引擎;支持事務/行級鎖/外鍵約束自動災難恢復/AUTO_INCREMENT |
|
需要事務支持,並且有較高的並發讀取頻率 |
MEMORY |
為得到最快的響應時間,采用的邏輯存儲介質是系統內存 |
當mysqld守護進程崩潰時,所有的Memory數據都會丟失;不能使用BLOB和TEXT這樣的長度可變的數據類型 |
臨時表 |
MERGE |
是MyISAM類型的一種變種。合並表是將幾個相同的MyISAM表合並為一個虛表 |
|
常應用於日志和數據倉庫 |
ARCHIVE |
歸檔的意思,支持索引,擁有很好的壓縮機制 |
僅支持插入和查詢功能 |
經常被用來當做倉庫使用 |
索引我們分為四類:單列索引(普通索引,唯一索引,主鍵索引)、組合索引、全文索引、空間索引。
- 單列索引:一個索引只包含單個列,但一個表中可以有多個單列索引。 這里不要搞混淆了。
1、普通索引:MySQL中基本索引類型,沒有什么限制,允許在定義索引的列中插入重復值和空值,純粹為了查詢數據更快一點。
2、唯一索引:索引列中的值必須是唯一的,但是允許為空值,
3、主鍵索引:是一種特殊的唯一索引,不允許有空值。
- 組合索引:一個的索引包含多個列,只有在查詢條件中使用了這些字段的左邊字段時,索引才會被使用,使用組合索引時遵循最左前綴。會在后面的例子細說。
- 全文索引:要求只有在MyISAM引擎上才能使用,只能在CHAR、VARCHAR、TEXT類型字段上使用全文索引。就是在一堆文字中,通過其中的某個關鍵字等,就能找到該字段所屬的記錄行,比如有"你是個大煞筆,二貨 ..." 通過大煞筆,可能就可以找到該條記錄。這里說的是可能,因為全文索引的使用涉及了很多細節。具體文章
- 空間索引:空間索引是對空間數據類型的字段建立的索引,MySQL中的空間數據類型有四種,GEOMETRY、POINT、LINESTRING、POLYGON。
在創建空間索引時,使用SPATIAL關鍵字。
要求,引擎為MyISAM,創建空間索引的列,必須將其聲明為NOT NULL。具體細節看下面
四、索引使用
Ⅰ、在創建表時創建索引:
創建索引:單列索引(普通、唯一、主鍵)、組合索引、全文索引和空間索引。
格式:CREATE TABLE 表名[字段名 數據類型] [UNIQUE|FULLTEXT|SPATIAL|...] [INDEX|KEY] [索引名字] (字段名[length])
1、創建普通索引:
## 創建普通索引,創建索引時未指定索引的名,會自動幫我們用字段名當作索引名
CREATE TABLE book( id INT NOT NULL PRIMARY KEY, name VARCHAR(50) NOT NULL, author VARCHAR(20) NOT NULL, info VARCHAR(255) NULL, INDEX(author));
## 查看表的創建
SHOW CREATE TABLE book; -------------------------------結果---------------------------------- CREATE TABLE `book` ( `id` int(11) NOT NULL, `name` varchar(50) NOT NULL, `author` varchar(20) NOT NULL, `info` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `author` (`author`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
## 用EXPLAIN關鍵字,來查看索引是否正在被使用,並且輸出其使用的索引信息
EXPLAIN SELECT * FROM book WHERE author = 'nana';
---------------------------------結果--------------------------------
雖然表中沒數據,但是有EXPLAIN關鍵字,用來查看索引是否正在被使用,並且輸出其使用的索引的信息。
id:為SELECT的識別符。這是SELECT的查詢序列號,也就是一條語句中,該select是第幾次出現。在上面語句中,select只有一個,所以是1。
select_type:表示使用SELECT的查詢類型,SIMPLE表示為簡單的SELECT,不適用於UNION或子查詢,就是簡單的SELECT。也就是說該SELECT查詢時會使用索引。其他取值:
PRIMARY:最外面的SELECT,在有子查詢時,就會出現兩個以上的SELECT。
UNION:union(兩張表連接)中的第二個或后面的select語句。
SUBQUERY:在子查詢中,第二個SELECT。
table:數據表的名字。按照被讀取的先后順序排列,這里只查詢一張表,所以只顯示book。
type:指定本數據表和其他數據表之間的關聯關系,該表中所有符合檢索值的記錄都會被取出來和從上一個表中取出來的記錄作聯合。
ref用於連接程序使用鍵的最左前綴或者是該鍵不是 primary key 或 unique索引(換句話說,就是連接程序無法根據鍵值只取得一條記錄)的情況。當根據鍵值只查詢到少數幾條匹配的記錄時,這就是一個不錯的連接類型。(注意,個人這里不是很理解,百度了很多資料,全是大白話,等以后用到了這類信息時,在回過頭來補充,這里不懂對后面的影響不大。)可能的取值有 system、const、eq_ref、index和All。
possible_keys:MySQL在搜索數據記錄時可以選用的各個索引。目前表里有兩個索引一個是主鍵一個是anthor。因為目前表里沒有數據,所以主鍵索引未被使用。
key:實際選用的索引。
key_len:顯示了mysql使用索引的長度(也就是使用的索引個數),當 key 字段的值為 null時,索引的長度就是 null。注意,key_len的值可以告訴你在聯合索引中mysql會真正使用了哪些索引。
ref:給出關聯關系中另一個數據表中數據列的名字。常量(const),這里使用的是'nana',就是常量。
rows:MySQL在執行這個查詢時預計會從這個數據表里讀出的數據行的個數。
extra:提供了與關聯操作有關的信息,沒有則什么都不寫。
上面的一大堆東西能看懂多少看多少,我們最主要的是看 possible_keys 和 key 這兩個屬性,上面顯示了key為anthor。說明使用了索引。
2、創建唯一索引:
## 創建唯一索引
CREATE TABLE tab1( id INT(5) NOT NULL, name CHAR(20) NOT NULL, UNIQUE INDEX uniqId(id) );
## 查看表的創建
SHOW CREATE TABLE tab1; ---------------------------------結果-------------------------------- CREATE TABLE `tab1` ( `id` int(5) NOT NULL, `name` char(20) NOT NULL, UNIQUE KEY `uniqId` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
## 查看索引使用信息
EXPLAIN SELECT * FROM tab1 WHERE id = 1;
---------------------------------結果--------------------------------
EXPLAIN SELECT * FROM tab1 WHERE id = 2;
---------------------------------結果--------------------------------
可以看到,通過id查詢時,會使用唯一索引。並且還實驗了查詢一個沒有的id值,則不會使用索引,我覺得原因是所有的id應該會存儲到一個const tables中,如果沒有該id值,那么就沒有查找的必要了。
3、創建主鍵索引:
## 創建主鍵索引
CREATE TABLE tab2( id INT(4) NOT NULL, name char(20) DEFAULT NULL, PRIMARY KEY(id));
## 查看表的創建
SHOW CREATE TABLE tab2; ---------------------------------結果-------------------------------- CREATE TABLE `tab2` ( `id` int(4) NOT NULL, `name` char(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
## 插入數據,查看下索引的使用,不然沒有id的值索引不會被使用
INSERT INTO tab2 VALUES(1,'nana');
## 查看索引使用信息
EXPLAIN SELECT * FROM tab2 WHERE id = 1;
---------------------------------結果--------------------------------
4、創建組合索引:
## 創建組合索引
CREATE TABLE tab3( id INT(4) NOT NULL, name CHAR(20) NOT NULL, age INT(3) NOT NULL, info VARCHAR(255), INDEX multiIdx(id,name,age) );
## 查看表的創建
SHOW CREATE TABLE tab3; ---------------------------------結果-------------------------------- CREATE TABLE `tab3` ( `id` int(4) NOT NULL, `name` char(20) NOT NULL, `age` int(3) NOT NULL, `info` varchar(255) DEFAULT NULL, KEY `multiIdx` (`id`,`name`,`age`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
## 查看索引使用信息
EXPLAIN SELECT * FROM tab3 WHERE id = 1 AND name = 'nana';
---------------------------------結果--------------------------------
EXPLAIN SELECT * FROM tab3 WHERE age = 3 AND name = 'nana';
---------------------------------結果--------------------------------
最左前綴:組合索引遵從了最左前綴,利用索引中最左邊的列集來匹配行,這樣的列集稱為最左前綴。例如,這里由id、name和age3個字段構成的索引,索引行中就按id/name/age的順序存放,索引組合中的字段可以是(id,name,age)、(id,name)或者(id)。如果要查詢的字段不構成最左面的前綴原則,那么就不會用索引,比如,age或者(name,age)組合就不會使用索引查詢。
4、創建全文索引:
## 創建全文索引,支持的字段類型為CHAR、VARCHAR和TEXT,存儲引擎為MyISAM
CREATE TABLE tab4( id INT(4) NOT NULL, name CHAR(20) NOT NULL, age INT(3) NOT NULL, info VARCHAR(255), FULLTEXT INDEX fullTxtIdx(info) )ENGINE=MyISAM;
## 查看表的創建
SHOW CREATE TABLE tab4; ---------------------------------結果-------------------------------- CREATE TABLE `tab4` ( `id` int(4) NOT NULL, `name` char(20) NOT NULL, `age` int(3) NOT NULL, `info` varchar(255) DEFAULT NULL, FULLTEXT KEY `fullTxtIdx` (`info`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8
## 插入數據,查看下索引的使用
INSERT INTO tab4 VALUES(1,'AAA',3,'text is so good,hei,my name is black'),(2,'BBB',4,'my name is white');
## 全文搜索
## 未找到結果,不知道為什么
SELECT * FROM tab4 WHERE MATCH(info) AGAINST('white');
## 查看索引使用信息
EXPLAIN SELECT * FROM tab4 WHERE MATCH(info) AGAINST('white');
---------------------------------結果--------------------------------
5、創建空間索引:
## 創建空間索引
CREATE TABLE tab5( geo GEOMETRY NOT NULL, SPATIAL INDEX spatIdx(geo) )ENGINE=MyISAM;
## 查看表的創建
SHOW CREATE TABLE tab5; ---------------------------------結果-------------------------------- CREATE TABLE `tab5` ( `geo` geometry NOT NULL, SPATIAL KEY `spatIdx` (`geo`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8
Ⅱ、在創建表后創建索引:
## 在已經存在的表上創建索引
ALTER TABLE 表名 ADD[UNIQUE|FULLTEXT|SPATIAL] [INDEX|KEY] [索引名] (索引字段名(長度))
## 查看表的索引
SHOW INDEX FROM book;
---------------------------------結果--------------------------------
Table:創建索引的表。
Non_unique:表示索引是否唯一,其中1代表:非唯一索引, 0代表:唯一索引。
Key_name:索引名稱。
Seq_in_index:表示該字段在索引中的位置,單列索引該值為1,組合索引為每個字段在索引定義中的順序(這個只需要知道單列索引該值為1,組合索引為別的)。
Column_name:表示定義索引的列字段。
Sub_part:表示索引的長度,當字段值為null時,索引長度為null。
Null:表示該字段是否能為空值。
Index_type:表示索引類型。
## 為表添加索引
ALTER TABLE book ADD INDEX BkNameIdx(name(30));
## 查看表的索引
SHOW INDEX FROM book;
---------------------------------結果--------------------------------
## 使用CREATE INDEX創建索引
CREATE [UNIQUE|FULLTEXT|SPATIAL] [INDEX|KEY] 索引名稱 ON 表名(創建索引的字段名[length])
## 為book表增加一個普通索引info。字段為CHAR,VARCHAR類型時,索引length可以小於字段實際長度;如果是BLOB和TEXT類型,必須指定 length
CREATE INDEX BkInfoIdx ON book(info(10));
## 查看表的索引
SHOW INDEX FROM book;
---------------------------------結果--------------------------------
Ⅲ、刪除索引:
## 使用ALTER DROP刪除索引
ALTER TABLE 表名 DROP INDEX 索引名
## 刪除book表中的名稱為BkInfoIdx的索引
ALTER TABLE book DROP INDEX BkInfoIdx;
## 查看表的索引
SHOW INDEX FROM book;
---------------------------------結果--------------------------------
## 使用DROP INDEX刪除索引
DROP INDEX 索引名 ON 表名;
## 刪除book表中的名稱為BkNameIdx的索引
DROP INDEX BkNameIdx ON book;
## 查看表的索引
SHOW INDEX FROM book;
---------------------------------結果--------------------------------
五、總結
MySQL的索引到這里差不多就講完了,總結一下我們到目前為止應該知道哪些東西
1、索引是干嘛的?為什么要有索引?
這個很重要,需要自己理解一下,不懂可以多看幾遍索引介紹。
2、索引的分類:單列索引(普通索引、唯一索引和主鍵索引)、組合索引、全文索引和空間索引。
3、索引的使用:
給表中創建索引,添加索引,刪除索引。