简单理解为:
用来
加快
数据访问
磁盘
延伸思考一下,为什么不存在内存中?
- 断电保存
- 数据量
- 内存消耗
IO
这里延伸出来的问题就是:要想查询快,想办法提高IO查询效率
。
- 减少IO次数
- 减少IO量
磁盘预读
这里涉及到:
磁盘
磁盘,查询数据的时候会优先将索引加载到内存中。
唯一标识(Key),实际数据行中存储的值。
文件地址(数据记录)
offset:偏移量,在文件中的哪个位置
抽象为K-V,key + value组合
符合的数据结构:
数据散列
不均匀,会产生大量线性查询,比较浪费时间
解决思路:继续进化,让树保持平衡(经过左旋或者右旋让树平衡起来,AVL平衡二叉树)
最短子树和最长子树高度差不能超过1
为了保证平衡,在插入数据的时候必须进行旋转。通过插入性能的损失来换取查询性能的提升。
比较适用于写少读多
的场景。
但是如何读写差不多或者写比读多?
解决思路:继续进化,红黑树
最长子树只要不超过最短子树的两倍即可
- 查询性能和插入性能近似取得
平衡
原因:
解决思路:继续进化,二叉树变成多叉树
,把原来有序二叉树变成有序多叉树,进化为B树
每个节点都存储数据
,所有节点组成这棵树,并且叶子节点指针为null;不重复
的。访问也更迅速
。(可能访问一下就能得到我要的节点数据)三层B树,假设一个节点的内存空间大小是16KB,一个数据占用了1KB。那么三层就是 16 * 16 * 16 = 4096,对于数据库来说这个数据量太小了。
解决思路:
只有叶子节点存储数据
(B+数中有两个头指针:一个指向根节点,另一个指向关键字最小的叶节点),叶子节点包含了这棵树的所有数据,所有的叶子结点使用链表
相连,便于区间查找和遍历
,所有非叶节点起到索引作用
。不含有该关键字对应记录的存储地址
。三层B+树,假设一个节点的内存空间大小是16KB,一个数据占用了10B。那么三层大概就是 1600 * 1600 * 1600 = 4096000000,4千万数据。。。。
(一般情况下mysql B+树 3-4层。超过4层需要考虑分库分表)
延伸思考点:
key 值占用存储空间尽量少,取决于int或者vachar的长度。不过一般情况下都选择int。
双向链表
,支持范围查询是否是聚簇索引取决于数据与索引是否放在一起
向innodb插入数据的时候,必须包含一个索引key值。这个索引key值可以是
主键
。如果没有主键,那么就是唯一键
。如果没有唯一键,那么就是一个自生成的6字节的Rowid
。
延伸思考点
数据冗余
数据字段指向数据表记录地址。
- 当根据普通索引查询到聚簇索引的key值之后,再根据key值在聚簇索引中获取所有行记录,走了多棵B+树。
延伸思考点:
假如创建一个(a,b)的联合索引,那么它的索引树是这样的
可以看到a的值是有顺序的,1,1,2,2,3,3,而b的值是没有顺序的1,2,1,4,1,2。所以b = 2这种查询条件没有办法利用索引,因为联合索引首先是按a排序的,b是无序的。
同时我们还可以发现在a值相等的情况下,b值又是按顺序排列的,但是这种顺序是相对的。所以最左匹配原则遇上范围查询就会停止,剩下的字段都无法使用索引。例如a = 1 and b = 2 a,b字段都可以使用索引,因为在a值确定的情况下b是相对有序的,而a>1and b=2,a字段可以匹配上索引,但b值不可以,因为a的值是一个范围,在这个范围中b是无序的。
最左匹配原则:最左优先,以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like)就会停止匹配。
假如建立联合索引(a,b,c)
- a
- a,b
- a,b,c
参考:https://blog.csdn.net/sinat_41917109/article/details/88944290
select * from table_name where a = '1' and b = '2' and c = '3' select * from table_name where b = '2' and a = '1' and c = '3' select * from table_name where c = '3' and b = '2' and a = '1' ......
where子句几个搜索条件顺序调换不影响查询结果,因为Mysql中有查询优化器,会自动优化查询顺序
select * from table_name where a = '1' select * from table_name where a = '1' and b = '2' select * from table_name where a = '1' and b = '2' and c = '3'
都从最左边开始连续匹配,用到了索引.
select * from table_name where b = '2' select * from table_name where c = '3' select * from table_name where b = '1' and c = '3'
没有从最左边开始,最后查询没有用到索引,用的是全表扫描 .
select * from table_name where a = '1' and c = '3'
只用到了a列的索引,b列和c列都没有用到 .
select * from table_name where a like 'As%'; //前缀都是排好序的,走索引查询 select * from table_name where a like '%As'//全表查询 select * from table_name where a like '%As%'//全表查询
select * from table_name where a > 1 and a < 3 and b > 1;
多个列同时进行范围查找时,只有对索引最左边的那个列进行范围查找才用到B+树索引,也就是只有a用到索引,在1<a<3的范围内b是无序的,不能用索引,找到1<a<3的记录后,只能根据条件 b > 1继续逐条过滤
select * from table_name where a = 1 and b > 3;
a=1的情况下b是有序的,进行范围查找走的是联合索引
select * from table_name order by a,b,c limit 10;
因为b+树索引本身就是按照上述规则排序的,所以可以直接从索引中提取数据,然后进行回表操作取出该索引中不包含的列就好了
order by的子句后面的顺序也必须按照索引列的顺序给出,比如
select * from table_name order by b,c,a limit 10;
这种颠倒顺序的没有用到索引