B-Tree 索引
不同的存储引擎也可能应用不同的存储构造,i 如,NDB 集群存储引擎外部实现应用了 T -Tree 构造存储这种索引,即便其名字是 BTREE;InnoDB 应用的是 B +Tree。
B-Tree 通常一位这所有的值都是按顺序存储的,并且每一个叶子页道根的间隔雷同。下图大抵反馈了 InnoDB 索引是如何工作的。
为什么 mysql 索引要应用 B + 树,而不是 B 树,红黑树
看完下面的文章就能够了解为何 B -Tree 索引可能快速访问数据了。因为存储引擎不再须要进行全表扫描获取须要的数据,叶子节点蕴含了所有元素信息,每一个叶子节点指针都指向下一个节点,所以很适宜查找范畴数据。
索引对多个值进行排列的根据是 CREATE TABLE 语句中定义索引时的程序。
那么,索引排序的规定就是依照 last_name ,first_name ,dob 的程序来的。
能够应用 B-Tree 索引的查问类型
B-Tree 索引实用于全键值、键值范畴或键前缀查找。
键前缀查找只是用于依据最左前缀查找。
举个粒子:
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)
);
这个表的索引如下:
type 后果
type 后果值从好到坏顺次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般来说,得保障查问至多达到 range 级别,最好能达到 ref,否则就可能会呈现性能问题。
possible_keys:sql 所用到的索引
key:显示 MySQL 理论决定应用的键(索引)。如果没有抉择索引,键是 NULL
(1)全值匹配
全值匹配指的是和索引中的所有列进行匹配。
例如下面的 People 表的索引(last_name,first_name,dob)能够用于查找 last_name=’Cuba Allen’,first_name=’Chuang’,dob=’1996-01-01’的人。这就是应用了索引中的所有列进行匹配,即全值匹配。
mysql> EXPLAIN select * from People where last_name = 'aaa' and first_name = 'bbb' and dob='2020-11-20' \G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: People
partitions: NULL
type: ref
possible_keys: last_name
key: last_name <----- 能够看到这个 key 就是咱们定义的索引
key_len: 307
ref: const,const,const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
ERROR:
No query specified
(2)匹配最左前缀
能够只应用索引的第一个列进行匹配。
例如能够用于查找 last_name=’aaa’的人,即用于查找姓为 Zeng 的人,这里只应用了索引的最左列进行匹配,即匹配最左前缀。
mysql> EXPLAIN select * from People where last_name = 'aaa' \G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: People
partitions: NULL
type: ref
possible_keys: last_name
key: last_name <---- 应用了索引
key_len: 152
ref: const
rows: 3
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
ERROR:
No query specified
(3)匹配列前缀
能够只匹配某一列的值的结尾局部。
例如能够用于查找 last_name LIKE‘a%’的人,即用于查找所有以 Z 结尾的姓的人,这里只应用了索引最左列的前缀进行匹配,即匹配列前缀。
mysql> EXPLAIN select * from People where last_name = 'a%' \G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: People
partitions: NULL
type: ref
possible_keys: last_name
key: last_name <--- 应用了索引
key_len: 152
ref: const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
ERROR:
No query specified
(4)匹配范畴值
能够只实用索引的第一列查找合乎某个范畴内的数据。
例如能够用于查找 last_name BETWEEN‘aaa’AND‘aaabbbccc’的人,即用于查找姓在 aaa 和 aaabbbccc 之间的人,这里只应用了索引最左列的前缀进行范畴匹配,即匹配范畴值。
mysql> EXPLAIN select * from People where last_name BETWEEN 'aaa' and 'aaabbbccc'\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: People
partitions: NULL
type: range
possible_keys: last_name
key: last_name <--- 应用了索引
key_len: 152
ref: NULL
rows: 3
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
ERROR:
No query specified
(5)准确匹配某一列并范畴匹配另外一列
能够使第一列全匹配,第二列范畴匹配。
例如能够用于查找 last_name=’aaa’AND first_name LIKE’b%’的人,即用于查找姓是 Zeng,名字以 C 结尾的人,这里应用了索引的最左列准确匹配,第二列进行范畴匹配。
mysql> EXPLAIN select * from People where last_name = 'aaa' and first_name like 'b%'\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: People
partitions: NULL
type: range
possible_keys: last_name
key: last_name <--- 应用了索引
key_len: 304
ref: NULL
rows: 1
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
ERROR:
No query specified
(6)只拜访索引的查问
查问只需拜访索引,而无须拜访数据行。
例如 select last_name, first_name where last_name=’aaa’; 这里只查问索引所蕴含的 last_name 和 first_name 列,则毋庸读取数据行。
mysql> explain select last_name,first_name,dob from People where last_name = 'aaa'
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: People
partitions: NULL
type: ref
possible_keys: last_name
key: last_name
key_len: 152
ref: const
rows: 1
filtered: 100.00
Extra: Using index
1 row in set, 1 warning (0.00 sec)
ERROR:
No query specified
另外,索引还能够用于查问中的 order by 操作。如果 order by 子句满足后面列出的集中查问类型,则这个索引也能够满足对应的排序需要。
B-Tree 的限度
1)只能依照索引的最左列开始查找。
例如 People 表中的索引无奈用于查找 first_name 为’bbb’的人,也无奈查找某个特定生日的人,因为这两个列都不是最左数据列。
(2)只能依照索引最左列的最左前缀进行匹配。
例如 People 表中的索引无奈查找 last_name LIKE‘%b’的人,尽管 last_name 就是此索引的最左列,但 MySQL 索引无奈查找以‘b’结尾的 last_name 的记录。
(3)只能依照索引定义的程序从左到右进行匹配,不能跳过索引中的列。
例如 People 表中的索引无奈用于查找 last_name=’a’AND bod=’1996-01-01’的人,因为 MySQL 无奈跳过索引中的某一列而应用索引中最左列和排在开端的列进行组合。如果不指定索引中两头的列,则 MySQL 只能应用索引的最左列,即第一列。
(4)如果查问中有某个列的范畴查问,则其左边所有列都无奈应用索引优化查找。
例如有这样一个查问:where last_name=’a’AND first_name LIKE’b%’AND dob=’1996-01-01’; 这个查问只能应用索引的前两列,因为这里 LIKE 是一个范畴条件,则 first_name 前面的索引列都将生效。(优化点:尽量不要在索引列中应用 LIKE 等范畴条件,改用多个等于条件来代替,保障前面的索引列能失效。)
MysQL EXPLAIN 详解
如何查看 sql 查问是否用到索引 \(mysql\)
参考书籍:高性能 MySQL