今天看了一篇關於mysql索引的部落格,感覺內容寫的非常不錯,但是排版說實話看得我頭疼,所以將其轉載過來,重新排了一下版,也是防止以後忘了的話可以方便重新溫習
部落格地址:www.cnblogs.com/whgk/p/6179…
一、什麼是索引?為什麼要建立索引?
索引用於快速找出在某個列中有一特定值的行,不使用索引,MySQL必須從第一條記錄開始讀完整個表,直到找出相關的行,表越大,查詢資料所花費的時間就越多,如果表中查詢的列有一個索引,MySQL能夠快速到達一個位置去搜尋資料檔案,而不必檢視所有資料,那麼將會節省很大一部分時間。
例如:有一張person表,其中有2W條記錄,記錄著2W個人的資訊。有一個Phone的欄位記錄每個人的電話號碼,現在想要查詢出電話號碼為xxxx的人的資訊。
如果沒有索引,那麼將從表中第一條記錄一條條往下遍歷,直到找到該條資訊為止。
如果有了索引,那麼會將該Phone欄位,通過一定的方法進行儲存,好讓查詢該欄位上的資訊時,能夠快速找到對應的資料,而不必在遍歷2W條資料了。其中MySQL中的索引的儲存型別有兩種:BTREE、HASH。
也就是用樹或者Hash值來儲存該欄位,要知道其中詳細是如何查詢的,就需要會演算法的知識了。我們現在只需要知道索引的作用,功能是什麼就行。
二、MySQL中索引的優點和缺點和使用原則
優點:
- 所有的MySql列型別(欄位型別)都可以被索引,也就是可以給任意欄位設定索引
- 大大加快資料的查詢速度
缺點:
- 建立索引和維護索引要耗費時間,並且隨著資料量的增加所耗費的時間也會增加
- 索引也需要佔空間,我們知道資料表中的資料也會有最大上線設定的,如果我們有大量的索引,索引檔案可能會比資料檔案更快達到上線值
- 當對錶中的資料進行增加、刪除、修改時,索引也需要動態的維護,降低了資料的維護速度。
使用原則:
通過上面說的優點和缺點,我們應該可以知道,並不是每個欄位度設定索引就好,也不是索引越多越好,而是需要自己合理的使用。
- 對經常更新的表就避免對其進行過多的索引,對經常用於查詢的欄位應該建立索引,
- 資料量小的表最好不要使用索引,因為由於資料較少,可能查詢全部資料花費的時間比遍歷索引的時間還要短,索引就可能不會產生優化效果。
- 在一同值少的列上(欄位上)不要建立索引,比如在學生表的"性別"欄位上只有男,女兩個不同值。相反的,在一個欄位上不同值較多可是建立索引。 上面說的只是很片面的一些東西,索引肯定還有很多別的優點或者缺點,還有使用原則,先基本上理解索引,然後等以後真正用到了,就會慢慢知道別的作用。注意,學習這張,很重要的一點就是必須先得知道索引是什麼,索引是幹嘛的,有什麼作用,為什麼要索引等等,如果不知道,就重複往上面看看寫的文字,好好理解一下。一個表中很夠建立多個索引,這些索引度會被存放到一個索引檔案中(專門存放索引的地方)
三、索引的分類
注意:索引是在儲存引擎中實現的,也就是說不同的儲存引擎,會使用不同的索引
MyISAM和InnoDB儲存引擎:只支援BTREE索引, 也就是說預設使用BTREE,不能夠更換
MEMORY/HEAP儲存引擎:支援HASH和BTREE索引
索引我們分為四類來講
單列索引(普通索引,唯一索引,主鍵索引)、組合索引、全文索引、空間索引
單列索引:
一個索引只包含單個列,但一個表中可以有多個單列索引。 這裡不要搞混淆了。
- 普通索引: MySQL中基本索引型別,沒有什麼限制,允許在定義索引的列中插入重複值和空值,純粹為了查詢資料更快一點。
- 唯一索引: 索引列中的值必須是唯一的,但是允許為空值,
- 主鍵索引: 是一種特殊的唯一索引,不允許有空值。
組合索引
在表中的多個欄位組合上建立的索引,只有在查詢條件中使用了這些欄位的左邊欄位時,索引才會被使用,使用組合索引時遵循最左字首集合。這個如果還不明白,等後面舉例講解時在細說
全文索引
全文索引,只有在MyISAM引擎上才能使用,只能在CHAR,VARCHAR,TEXT型別欄位上使用全文索引,介紹了要求,說說什麼是全文索引,就是在一堆文字中,通過其中的某個關鍵字等,就能找到該欄位所屬的記錄行,比如有"好人,二貨 ..."
通過好人,可能就可以找到該條記錄。這裡說的是可能,因為全文索引的使用涉及了很多細節,我們只需要知道這個大概意思,如果感興趣進一步深入使用它,那麼看下面測試該索引時,會給出一個博文,供大家參考。
空間索引
空間索引是對空間資料型別的欄位建立的索引,MySQL中的空間資料型別有四種,GEOMETRY、POINT、LINESTRING、POLYGON。在建立空間索引時,使用SPATIAL關鍵字。要求,引擎為MyISAM,建立空間索引的列,必須將其宣告為NOT NULL。具體細節看下面
四、索引操作(建立和刪除)
建立索引
- 建立表的時候建立索引
格式:CREATE TABLE 表名[欄位名 資料型別] [UNIQUE|FULLTEXT|SPATIAL|...] [INDEX|KEY] [索引名字] (欄位名[length]) [ASC|DESC]
|--------------------------------------| |-----------------------------------| |------------| |---------| |---------------| |------------|
普通建立表語句 設定什麼樣的索引(唯一、全文等) 索引關鍵字 索引名字 對哪個欄位設定索引 對索引進行排序
- 建立普通索引
CREATE TABLE book
(
bookid INT NOT NULL,
bookname VARCHAR(255) NOT NULL,
authors VARCHAR(255) NOT NULL,
info VARCHAR(255) NULL,
comment VARCHAR(255) NULL,
year_publication YEAR NOT NULL,
INDEX(year_publication)
)
CREATE TABLE book
(
bookid INT NOT NULL,
bookname VARCHAR(255) NOT NULL,
authors VARCHAR(255) NOT NULL,
info VARCHAR(255) NULL,
comment VARCHAR(255) NULL,
year_publication YEAR NOT NULL,
KEY(year_publication)
)
複製程式碼
上面兩種方式建立度可以,通過這個例子可以對比一下格式,就差不多明白格式是什麼意思了。
通過列印結果,我們在建立索引時沒寫索引名的話,會自動幫我們用欄位名當作索引名。 測試:看是否使用了索引進行查詢。
SELECT * FROM book WHERE year_publication = 1990\G;
複製程式碼
解釋:雖然表中沒資料,但是有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在搜尋資料記錄時可以選用的各個索引,該表中就只有一個索引,y
ear_publication
key:實際選用的索引
key_len:顯示了mysql使用索引的長度(也就是使用的索引個數),當key欄位的值為null
時,索引的長度就是null。注意,key_len的值可以告訴你在聯合索引中mysql會真正使用
了哪些索引。這裡就使用了1個索引,所以為1,
ref:給出關聯關係中另一個資料表中資料列的名字。常量(const),這裡使用的是1990
,就是常量。
rows:MySQL在執行這個查詢時預計會從這個資料表裡讀出的資料行的個數。
extra:提供了與關聯操作有關的資訊,沒有則什麼都不寫。
上面的一大堆東西能看懂多少看多少,我們最主要的是看possible_keys和key 這兩個屬性,上面顯示了key為year_publication。說明使用了索引。
複製程式碼
- 建立唯一索引
CREATE TABLE t1
(
id INT NOT NULL,
name CHAR(30) NOT NULL,
UNIQUE INDEX UniqIdx(id)
)
複製程式碼
解釋:對id欄位使用了索引,並且索引名字為UniqIdx。
SHOW CREATE TABLE t1\G;
複製程式碼
要檢視其中查詢時使用的索引,必須先往表中插入資料,然後在查詢資料,不然查詢一個沒有的id值,是不會使用索引的。
INSERT INTO t1 VALUES(1,'xxx');
EXPLAIN SELECT * FROM t1 WHERE id = 1\G;
複製程式碼
可以看到,通過id查詢時,會使用唯一索引。並且還實驗了查詢一個沒有的id值,則不會使用索引,我覺得原因是所有的id應該會儲存到一個const tables中,到其中並沒有該id值,那麼就沒有查詢的必要了。
- 建立主鍵索引
CREATE TABLE t2
(
id INT NOT NULL,
name CHAR(10),
PRIMARY KEY(id)
);
INSERT INTO t2 VALUES(1,'QQQ');
EXPLAIN SELECT * FROM t2 WHERE id = 1\G;
複製程式碼
通過這個主鍵索引,我們就應該反應過來,其實我們以前宣告的主鍵約束,就是一個主鍵索引,只是之前我們沒學過,不知道而已。
- 建立單列索引
這個其實就不用在說了,前面幾個就是單列索引。
*建立組合索引
組合索引就是在多個欄位上建立一個索引
建立一個表t3,在表中的id、name和age欄位上建立組合索引
CREATE TABLE t3
(
id INT NOT NULL,
name CHAR(30) NOT NULL,
age INT NOT NULL,
info VARCHAR(255),
INDEX MultiIdx(id,name,age)
);
SHOW CREATE t3\G;
複製程式碼
解釋最左字首
組合索引就是遵從了最左字首,利用索引中最左邊的列集來匹配行,這樣的列集稱為最左字首,不明白沒關係,舉幾個例子就明白了,例如,這裡由id、name和age3個欄位構成的索引,索引行中就按id/name/age的順序存放,索引可以索引下面欄位組合(id,name,age)、(id,name)或者(id)。如果要查詢的欄位不構成索引最左面的字首,那麼就不會是用索引,比如,age或者(name,age)組合就不會使用索引查詢
在t3表中,查詢id和name欄位
EXPLAIN SELECT * FROM t3 WHERE id = 1 AND name = 'joe'\G;
複製程式碼
在t3表中,查詢(age,name)欄位,這樣就不會使用索引查詢。來看看結果
EXPLAIN SELECT * FROM t3 WHERE age = 3 AND name = 'bob'\G;
複製程式碼
- 建立全文索引
全文索引可以用於全文搜尋,但只有MyISAM儲存引擎支援FULLTEXT索引,並且只為CHAR、VARCHAR和TEXT列服務。索引總是對整個列進行,不支援字首索引,
CREATE TABLE t4
(
id INT NOT NULL,
name CHAR(30) NOT NULL,
age INT NOT NULL,
info VARCHAR(255),
FULLTEXT INDEX FullTxtIdx(info)
)ENGINE=MyISAM;
SHOW CREATE TABLE t4\G;
複製程式碼
使用一下什麼叫做全文搜尋。就是在很多文字中,通過關鍵字就能夠找到該記錄。
INSERT INTO t4 VALUES
(8,'AAA',3,'text is so good,hei,my name is bob')
,(9,'BBB',4,'my name is gorlr');
SELECT * FROM t4 WHERE MATCH(info) AGAINST('gorlr');
複製程式碼
EXPLAIN SELECT * FROM t4 WHERE MATCH(info) AGAINST('gorlr');
複製程式碼
注意:在使用全文搜尋時,需要藉助MATCH函式,並且其全文搜尋的限制比較多,比如只能通過MyISAM引擎,比如只能在CHAR,VARCHAR,TEXT上設定全文索引。比如搜尋的關鍵字預設至少要4個字元,比如搜尋的關鍵字太短就會被忽略掉。等等,如果你們在實驗的時候可能會實驗不出來。感興趣的同學可以看看這篇文章,全文搜尋的使用
- 建立空間索引
空間索引也必須使用MyISAM引擎, 並且空間型別的欄位必須為非空。
這個空間索引具體能幹嘛我也不知道,可能跟遊戲開發有關,可能跟別的東西有關,等遇到了自然就知道了,現在只要求能夠建立出來。
CREATE TABLE t5
(
g GEOMETRY NOT NULL,
SPATIAL INDEX spatIdx(g)
) ENGINE = MyISAM;
SHOW CREATE TABLE t5\G;
複製程式碼
- 在已經存在的表上建立索引
格式:ALTER TABLE 表名 ADD[UNIQUE|FULLTEXT|SPATIAL] [INDEX|KEY] [索引名] (索引欄位名)[ASC|DESC] 有了上面的基礎,這裡就不用過多陳述了。
命令一:
SHOW INDEX FROM 表名\G
複製程式碼
檢視一張表中所建立的索引
SHOW INDEX FROM book\G;
複製程式碼
挑重點講,我們需要了解的就5個,用紅顏色標記了的,如果想深入瞭解,可以去查查該方面的資料,我個人覺得,這些等以後實際工作中遇到了在做詳細的瞭解把。
Table:建立索引的表
Non_unique:表示索引非唯一,1代表非唯一索引,0代表唯一索引,意思就是該索引是不是唯一索引
Key_name:索引名稱
Seq_in_index :表示該欄位在索引中的位置,單列索引的話該值為1,組合索引為每個欄位在索引定義中的順序(這個只需要知道單列索引該值就為1,組合索引為別的)
Column_name:表示定義索引的列欄位
Sub_part:表示索引的長度
Null:表示該欄位是否能為空值
Index_type:表示索引型別
複製程式碼
- 為表新增索引
就拿上面的book表來說。本來已經有了一個year_publication,現在我們為該表在加一個普通索引
ALTER TABLE book ADD INDEX BkNameIdx(bookname(30));
複製程式碼
看輸出結果,就能知道,新增索引成功了。
這裡只是拿普通索引做個例子,新增其他索引也是一樣的。依葫蘆畫瓢而已。這裡就不一一做講解了。
- 使用CREATE INDEX建立索引
格式:CREATE [UNIQUE|FULLTEXT|SPATIAL] [INDEX|KEY] 索引名稱 ON 表名(建立索引的欄位名[length])[ASC|DESC]
解釋:其實就是換湯不換藥,格式改變了一下而已,做的事情跟上面完全一樣,做一個例子。
在為book表增加一個普通索引,欄位為authors。
CREATE INDEX BkBookNameIdx ON book(bookname);
複製程式碼
SHOW INDEX FROM book\G;  //檢視book表中的索引
複製程式碼
解釋:第一條截圖沒截到,因為圖太大了,這裡只要看到有我們新加進去的索引就證明成功了。。其他索引也是一樣的建立。
刪除索引
前面講了對一張表中索引的新增,查詢的方法。
新增的兩種方式
1在建立表的同時如何建立索引,
2在建立了表之後如何給表新增索引的兩種方式,
查詢的方式
SHOW INDEX FROM 表名\G;
複製程式碼
\G只是讓輸出的格式更好看
現在來說說如何給表刪除索引的兩種操作。
- 格式一:ALTER TABLE 表名 DROP INDEX 索引名
很簡單的語句,現在通過一個例子來看看,還是對book表進行操作,刪除我們剛才為其新增的索引。
1、刪除book表中的名稱為BkBookNameIdx的索引。
ALTER TABLE book DROP INDEX BkBookNameIdx;
複製程式碼
SHOW INDEX FROM book\G;  //在檢視book表中的索引,就會發現BkBookNameIdx這個索引已經不在了
複製程式碼
- 格式二:DROP INDEX 索引名 ON 表名
刪除book表中名為BkNameIdx的索引
DROP INDEX BkNameIdx ON book;
SHOW INDEX FROM book\G;
複製程式碼