目录
一:B + 树
- 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数据是在页中如何存储的呢?
"""
在页的用户数据区域存储数据,在插入数据的时候,根据索引插入对应的位置,这样方便查询的效率,但是插入的时候需要遍历,影响插入效率。
"""
如何提高页的查询效率?长链表提高查询效率:用空间换时间,采用页目录。
"""
我们将链表划分成多组,我们采用页目录记录每组的最小的地址。此时我们查询数据的时候,先看在那一组中,然后再在组中遍历出数据。
"""
目录也可能比较多:目录的顺序由于都是有序的,因此可以采用二分查找来进行查找。
4:如果这个页存储的数据满了怎么办?
"""
案例: 如果查询 select * from table_1 where id = 7:
如何查询呢?
"""
5:如果这个页又有很多呢?则页和页之间又是个长链表,此时可能又很慢了。
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数据引擎下,主键索引是跟用户的数据存储在一起的,而现在需要新的数据排列,就需要拷贝一份新的额数据。
2:真正的联合索引的建立规则:
联合索引建立的B+树,叶子结点存储的是联合索引字段的值以及对应的主键索引。
案例: 例如查询:select * from table_1 where b = 1, c = 1, d = 1; 我们首选先在联合索引中查询,查到111这个叶子结点后,我们查询到这个记录的id 例如:id=4 ,我们再回表,在主键索引下继续查询这个字段的完整信息。
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。