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: refpossible_keys: last_name key: last_name <-----能够看到这个key就是咱们定义的索引 key_len: 307 ref: const,const,const rows: 1 filtered: 100.00 Extra: NULL1 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: refpossible_keys: last_name key: last_name <----应用了索引 key_len: 152 ref: const rows: 3 filtered: 100.00 Extra: NULL1 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: refpossible_keys: last_name key: last_name <---应用了索引 key_len: 152 ref: const rows: 1 filtered: 100.00 Extra: NULL1 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: rangepossible_keys: last_name key: last_name <---应用了索引 key_len: 152 ref: NULL rows: 3 filtered: 100.00 Extra: Using index condition1 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: rangepossible_keys: last_name key: last_name <---应用了索引 key_len: 304 ref: NULL rows: 1 filtered: 100.00 Extra: Using index condition1 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: refpossible_keys: last_name key: last_name key_len: 152 ref: const rows: 1 filtered: 100.00 Extra: Using index1 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