一:B + 树

MYSQL索引的底层原理_字段

  • 1: 叶子结点是有指针的。
  • 2:叶子结点是有所有元素的,非叶子结点和叶子结点元素有冗余。
  • 3:叶子结点可以存储多个元素。

二:索引的原理:

1: 操作系统的页的概念:

"""
操作系统中定义一页 = 4K, 操作系统执行指令的时候要遵循局部性原理,一次IO操作要磁盘中至少读取4k的数据。
"""

2:innodb中页的概念:

"""
innodb 是存储引擎,在innodb中定义一页是16K,也就是innodb读取数据,一次至少读取16K的数据。
"""
案例: 假设执行下面的sql语句:
select * from table_1 where id = 6;
如果没有页的概念,他会一次读取一条数据到内存中,然后内存中比较是否符合条件,不符合则再次读取磁盘的下一条数据。假设这条数据是第六条,则需要执行6次磁盘IO操作。
如果有了页的概念,我们只需要执行一次IO操作,读取16K的数据到内存中,在内存中比较这16k的数据,这样就减少了磁盘的IO次数。

3:mysql数据是在页中如何存储的呢?

MYSQL索引的底层原理_主键_02

"""
在页的用户数据区域存储数据,在插入数据的时候,根据索引插入对应的位置,这样方便查询的效率,但是插入的时候需要遍历,影响插入效率。
"""

如何提高页的查询效率?长链表提高查询效率:用空间换时间,采用页目录。

"""
我们将链表划分成多组,我们采用页目录记录每组的最小的地址。此时我们查询数据的时候,先看在那一组中,然后再在组中遍历出数据。
"""

目录也可能比较多:目录的顺序由于都是有序的,因此可以采用二分查找来进行查找。

4:如果这个页存储的数据满了怎么办?

MYSQL索引的底层原理_主键_03

"""
案例: 如果查询 select * from table_1 where id = 7:
如何查询呢?
"""

5:如果这个页又有很多呢?则页和页之间又是个长链表,此时可能又很慢了。

MYSQL索引的底层原理_主键_04

6: 为什么指针是双向的?

"""
如果是单向指针,我们执行select * from table_1 where id > 8; 可以通过单向指针遍历到。
但是如果select * from table_1 where id < 8;这种情况,我们是无法遍历到,当我们找到id = 8的还要通过计算寻找 id = 7的再次走一遍查询的过程,效率很低。 
"""

二:InnoDB中联合索引生成的过程

  • create index index_1 on table_1(b,c, d): 对B, C ,D建立索引。
  • 主键索引B+ 树是根据插入的时候不断的建立的,但是联合索引是创建的时候生成的。

1:建立联合索引的一种思路:

我们只需要根据联合索引的字段进行排序,然后生成B+树就可以了。但是这种思路存在一种致命的问题:就是我们需要拷贝一份原有的数据。因为在innodb数据引擎下,主键索引是跟用户的数据存储在一起的,而现在需要新的数据排列,就需要拷贝一份新的额数据。

MYSQL索引的底层原理_字段_05

2:真正的联合索引的建立规则:

联合索引建立的B+树,叶子结点存储的是联合索引字段的值以及对应的主键索引。

案例: 例如查询:select * from table_1 where b = 1, c = 1, d = 1; 我们首选先在联合索引中查询,查到111这个叶子结点后,我们查询到这个记录的id 例如:id=4 ,我们再回表,在主键索引下继续查询这个字段的完整信息。

MYSQL索引的底层原理_字段_06

3:最左前缀原则:

就是如果我要利用联合索引,我的查询语句中的第一个必须是联合索引的第一个。

假设我们对(b, c, d)建立索引:

select * from table_1 where b = 1;这个是可以利用索引的。

select * from table_1 where c= 1, d = 2; 这个是不能利用索引的。

select * from table_1 where b > 1; 这个可以利用索引吗?

答:可以走索引,但是不一定走索引。因为如果我走联合索引,经过这个联合索引,我拿到是大于b的所有的主键,假设大于b的有一万条数据,我们需要回表一万次才能查询全部的数据。这样还不如进行全表扫描呢。但是如果b>1的只有两三个数据,此时是可以走联合索引的。数据库引擎会权衡两种,寻找最优。

对于select b from table_1 where b > 1: 这个走索引吗?

答: 一定是走索引的,因为我们这一次是查询的b 这个字段,而联合索引中存储了这个信息,我一次回表也不需要,索引一定走联合索引。

对于 select b, c, d, id from table_1 where b>1;这个走索引吗?

答:一定走索引:因为这几个字段联合索引中也是存在的。

对于 select b from table_1;这个走索引吗?

答:两个都可以,但是走联合索引更快,所以选择联合索引。因为联合索引的存储量少,导致我存储的页数比较少,就减少磁盘的IO次数。

注意:在mysql中:

  • ‘1’ = 1 是对的。
  • ‘a’ = 0 也是对的。
  • ‘a’ = 1 是错的,因为在mysql中将字符是数字的转换成数字,将字符不是数字的转换成0。