簡介:
索引可以包含一個或多個列的值。如果索引包含多個列,那麼列的順序也十分重要。MySQL只能高效地使用索引的最左前綴列。下面會有詳細的介紹。
大家都知道索引能讓服務器快速定位到表的指定位置,但這不是索引的唯一作用。使用索引有如下三大優點:
- 索引大大減少了服務器需要掃描的數據量。
- 索引可以幫助服務器避免排序和臨時表。
- 索引可以講隨機I/O變爲順序IO。
一、索引類型
1. B+樹索引(btree索引)
B+樹索引是最爲常用的,也是最有效的索引。B+樹最早是從平衡二叉樹演化過來的,但不是二叉樹。B+樹通常意味着所有的值都是按順序存儲的,並且每個葉子頁到根的距離相同。
注意:B+樹索引不能找到一個給定值的具體行,只能找到被查找數據行所在的頁。數據庫把頁讀到內存,在內存中搜索需要查找的數據。
下圖展示了b+樹索引的抽象表示(圖片來源:高性能mysql第三版):
B+樹索引分爲兩種:
- 聚集索引
按照每張表的主鍵構造一顆B+樹,葉子節點存放整張表的行記錄數據,也將聚集索引的葉子節點成爲數據頁。 - 輔助索引
輔助索引也稱非聚集索引,葉子節點不包含行記錄的全部數據,每個節點包含一個書籤(bookmark),該書籤存儲了相應行數據的聚集索引鍵。
2. hash索引
InnoDB支持的hash索引是自適應的(自適應哈希索引,Adaptive Hash Index, AHI),InnoDB會根據表的使用情況,自動爲表生成hash索引,不能人爲干預。
hash索引只能用於等值查詢,例如:select x from xxxx where xx = xxx
, 其他查詢不支持(比如:where xx > xxx
)
# 查看當前hash索引使用情況
show engine innodb status
# 查看AHI是否啓用 默認啓用ON,如若想關閉,將ON改爲OFF
show variables like 'innodb_adaptive_hash_index'
3. 全文索引
全文索引是一種特殊類型的索引,它查找的是文本中的關鍵詞,而不是直接比較索引中的值。MySQL5.6以後,innodb支持全文索引
在相同列上同時創建全文索引和B+樹索引不會有衝突,適用於Match Against操作,而不是普通的where條件操作。
使用全文索引
# 創建文章表,指定使用InnoDB引擎,title、content添加全文索引
CREATE TABLE articles (
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(200),
content TEXT,
FULLTEXT (title,content)
) ENGINE=InnoDB CHARACTER SET utf8mb4;
# 插入十萬條數據(測試全文索引查詢效率,多插點數據。這裏使用存儲函數)
# 對存儲過程不熟悉的,可以看下我另一篇博客
# https://blog.csdn.net/hhy107107/article/details/81269946
delimiter ;;
CREATE procedure insert_more ()
BEGIN
DECLARE i int DEFAULT 1;
WHILE i < 100000
DO
INSERT INTO articles(id, title, content) values (null, 'title', REPEAT('content',7000));
SET i = i + 1;
END WHILE;
COMMIT;
END;;
delimiter ;
# 執行插入
call insert_more
# 隨便往其中一條記錄的content字段的內容中加測試兩個字
# 普通查詢,不走索引
[SQL] SELECT * FROM articles WHERE content like '%測試%'
受影響的行: 0
時間: 44.967s
# 使用全文索引
[SQL] SELECT * FROM articles WHERE MATCH (title,content) AGAINST ('測試' IN boolean MODE);
受影響的行: 0
時間: 0.195s
二、組合索引
- 組合索引 一個索引包含多個列
現有一個people表, 有一個組合索引,包含三個列
create table people (
last_name varchar(50) not null,
first_name varchar(50) not null,
dob date not null,
gender enum('m', 'f') not null,
key(last_name, first_name, dob)
)
上表建的索引,對如下類型的查詢有效
- 全值匹配
可以用於查找姓xx,名xx,出生於xx的人 - 匹配最左前綴
可以用於查找姓xx的人,即只使用索引的第一列 - 匹配列前綴
可以匹配某一列的值的開頭部分。例如可以查找姓氏爲X頭的人 - 匹配範圍值
可以查找姓X和XX之間的人 - 精確匹配某一列並範圍匹配另外一列
可以匹配姓X名字X開頭的人,即last_name
全匹配,first_name
範圍匹配 - 只訪問索引的查詢
查詢只需要訪問索引,無需訪問數據行
索引查詢的限制
- 如果不是從索引的最左列開始查找,不能使用索引。
例如,上表不能用索引查詢first_name
爲x的人,也不能查出生於X的人。因爲這兩列不是最左數據列。也無法查詢姓氏以X結尾的人。 - 不能跳列索引
也就是說不能查詢姓X,出生於XX的人,如果不指定名,只能索引姓,不能索引出生日期。 - 如果查詢的某個列是範圍查詢,其右邊的列無法索引。
例如,where last_name = 'x' and first_name like 'J%' and dob = 'xx'
這個查詢,只能索引last_name
和first_name
,不能索引dob
三、其他
1.索引設計原則
- 最適合建索引的列是where子句後面的列和連接子句中指定的列。
- 使用唯一索引。考慮某列中值的分佈。對於唯一值的列,索引效果最好,具有多個重複值的列,索引效果最差。比如記錄性別的列,此列值只有‘M’,‘F’,對此列索引沒多大用,不管搜哪個,都回得出大約一半的行。
- 使用短索引。例如有個char(200)的列,列值前10的值多數都是唯一的,那麼就不要對整列進行索引,只對列的前10個字符索引
2.不能使用索引的情況
- 如果mysql查詢的列不是獨立的,不能使用索引。索引列不能是表達式的一部分,也不能是函數的參數。
例如:select user_id from user where user_id + 1 = 5
;
3.索引提示
mysql 支持索引提示(index hint),顯式的告訴優化器使用哪個索引。
當某條sql語句可以選擇的索引非常多,優化器選擇執行計劃的時間開銷可能會比較大。這時候,我們可以強制讓優化器不進行執行路徑的成本分析,直接使用指定的索引進行查詢
# 指定使用firstName索引 firstName是索引名稱
SELECT * FROM `user` force index (firstName) WHERE last_name = '姓氏' and first_name = '名字';
# 使用explain關鍵字查看執行計劃 結果中,possible_keys爲可選擇的索引, key表示當前使用的索引
explain SELECT * FROM `user` force index (firstName) WHERE last_name = '姓氏' and first_name = '名字';
Mysql InnoDB介紹
https://blog.csdn.net/hhy107107/article/details/82703926
MySQL 存儲過程
https://blog.csdn.net/hhy107107/article/details/81269946
[1]姜承堯 .MySQL技術內幕:InnoDB存儲引擎 機械工業出版社
[2]高性能MySQL 第三版:電子工業出版社