《Mysql是怎样运行的》读书笔记之B+树索引的使用

索引具有时间和空间上的代价。
空间上的代价:每建立一个索引,都会建立一棵B+树,每一棵B+树的每个节点都是一个数据页,一个数据页会默认占用16KB的存储空间,一棵很大的B+树由很多数据页组成,这将占用很大一片空间。
时间上的代价:每当对表中的数据进行增删改查操作时,都需要修改各个B+树索引。存储引擎需要额外的时间进行页面 分裂,页面回收等操作,以维护节点和记录的排序。

扫描区间和边界条件

select * from single_table where id>=2 and id<=100;

比如上面语句中,与扫描全部的聚簇索引相比,扫描id值在[2,100]区间中中的记录数据已经很大程度上减少了需要扫描的数量,所以提高了查询效率。
我们把只包含一个值的扫描区间称为单点扫描区间。
包含多个值的扫描区间称为范围扫描区间。

如果想使用某个索引来执行查询,但是又无法通过搜索条件形成合适的扫描区间来减少需要扫描的数量的时,则不考虑使用这个索引执行查询 。

对于B+树索引来说,只要索引列和常数使用=<=>INNOT INIS NULLIS NOT NULL><>=<=BETWEEN!=或者LIKE操作符连接起来,就可以产生所谓的扫描区间。不过有些需要注意:

  • IN操作符的语义与若干个等值匹配操作符(=)之间用OR连接起来的语义是一样的。
  • !=产生的扫描区间容易被忽略。比如:
    select * from single_table where id != 2 ; 

此时的扫描区间是(-∞,2)(2,+∞)

  • LIKE操作符只有在匹配完整的字符串或者匹配的字符串的前缀才产生合适的扫描区间。

使用联合索引执行查询时对应的扫描区间

假设为表中的key_part1,key_part2,key_part3列建立idx_key_part二级索引。
先按着key_part1列的值排序,在key_part1列的值相同的情况下,再按照key_part2列的值排序,在key_part1列的值和key_part2列的值相同的情况下,再按照key_part3列的值排序。

  1. 对于查询语句:
select * from single_table where key_part1 = 'a' and key_part3 = 'c';

对于符合key_part1 = 'a'条件的二级索引记录,并不是直接按照key_part3列的值进行排序的。我们若想使用idx_key_part索引。可以定位到key_part1 = 'a'的第一条记录,然后沿着记录所在链表向后扫描。所以这个扫描区间是['a','a']

  1. 对于查询语句:
select * from single_table where key_part1 < 'b' and key_part2 = 'a';

对于符合key_part1 < 'b'条件的二级索引记录,并不是直接按照key_part2列的值进行排序的。我们不能根据key_part2 = 'a'进一步减少需要扫描的记录数量。所以这个扫描区间是(-∞,'b')
3. 对于查询语句:

select * from single_table where key_part1 <= 'b' and key_part2 = 'a';

对于符合 key_part1 < 'b'条件的二级索引记录,并不是直接按照key_part2列的值进行排序的。
但是对于符合 key_part1 = 'b'条件的二级索引记录时,是按照key_part2列的值排序的。当扫描到第一条不符合key_part1 <= 'b' and key_part2 = 'a'条件的第一条记录时,就可以结束扫描。
所以这个扫描 区间是[(-∞,-∞),('b','a')]

索引用于排序

  1. 使用联合索引是,ORDER BY子句后面的列顺序也必须按照索引列的顺序给出。

  2. 对于联合索引进行排序的场景,要求各个排序列的排列规则是一致的,要么是按照ASC(升序),要么是按照DESC(降序)排列规则。

使用ORDER BY进行降序排列是可以使用索引的。

  1. 排序列包含非同一个索引的列是不能使用索引的。
  2. 排序列是某个联合索引的索引列,但是排序列在联合索引中并不连续不能使用索引。
  3. 排序列不是以单独列名出现在ORDER BY子句中(可能是函数或者表达式修饰过的形式)不能使用索引。

你可能感兴趣的:(《Mysql是怎样运行的》读书笔记之B+树索引的使用)