为什么使用索引?
- 为什么要给表加上主键?
- 为什么加索引后会使查询变快?
- 为什么加索引后会使写入、修改、删除变慢?
- 什么情况下要同时在两个字段上建索引?
「索引就像书的目录, 通过书的目录就准确的定位到了书籍具体的内容」
索引的简介
我们平时建表的时候都会为表加上主键, 在某些关系数据库中, 如果建表时不指定主键,数据库会拒绝建表的语句执行,事实上, 一个加了主键的表,并不能被称之为「表」。一个没加主键的表,它的数据无序的放置在磁盘存储器上,一行一行的排列的很整齐。如果给表加了主键,那么表在磁盘上的存储结构就由整齐排列的结构转变成了树状结构
当这个sql执行当时候经历了:
1.一次性把根的数据由磁盘加载到内存块中,
2.在内存中用二分查找确定当前id在哪块区域
3.多次重复定位
4.取出结果返回
索引的本质
索引(Index)是帮助MySQL高效获取数据的数据结构。提取句子主干。索引是数据结构
索引采用的数据结构(Mysql)
1.Hash索引
2.B+ Tree
3.B Tree
以mysql为例子:我们使用的是InnoDB引擎,默认的是B+树。为啥?
1.磁盘IO读写次数相比B树降低了
在B+树中,其非叶子的内部节点都变成了key值,因此其内部节点相对B 树更小。如果把所有同一内部节点的key存放在同一盘块中,那么盘块所能容纳的key数量也越多。一次性读内存中的需要查找的key值也就越多。相对来说IO读写次数也就降低了。
2.每次查询的时间复杂度是固定的
在B+树中,由于分支节点只是叶子节点的索引,所以对于任意关键字的查找都必须从根节点走到分支节点,所有关键字查询路径长度相同,每次查询的时间复杂度是固定的。但是在B树中,其分支节点上也保存有数据,对于每一个数据的查询所走的路径长度是不一样的,所以查询效率也不一样。
3.遍历效率更高
由于B+树的数据都存储在叶子节点上,分支节点均为索引,方便扫库,只需扫一遍叶子即可。但是B树在分支节点上都保存着数据,要找到具体的顺序数据,需要执行一次中序遍历来查找。所以B+树更加适合范围查询的情况,在解决磁盘IO性能的同时解决了B树元素遍历效率低下的问题。
Hash索引
Hash索引底层是哈希表,哈希表是一种k/v存储数据的结构,因为结构是kv所以在检索效率上非常高。索引一次定位 不需要想BT索引多次io找到对应区间。效果高但是也有很多限制
- 仅满足 = in 和 <=> 查询不可以范围查询
- 无法用来避免数据排序 哈希值后的数值不能代表之前的数值
- 哈希索引不能利用部分索引键查询。对于组合的索引。它是把所有的索引键合并在一起hash的
- 任何时候都避免不了全表扫描
- hash索引遇到大量hash相等的情况下 性能并不一定就会比btree高
所以,哈希索引只适用于等值查询的场景
B-Tree
1。key的数据超过1024就会分裂,当一个节点的key满了就会
B+Tree
B+Tree 是BTree的变种。本质都是btree。每个节点的指针上限为2d而不是2d+1。内节点不存储data,只存储key;叶子节点不存储指针。B+ 树是一种多路平衡查询树,所以他的节点是天然有序的
聚簇索引、覆盖索引非聚簇索引**
聚簇索引:将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据
非聚簇索引:将数据与索引分开存储,索引结构的叶子节点指向了数据对应的位置
覆盖索引: 指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取。也可以称之为实现了索引覆盖
总结:聚簇比非聚簇快,因为少了一次,对地址的查询(聚簇索引叶子结点直接有行数据了),当然也不是肯定的 也可以通过覆盖索引改变, 例如 组合在一起把 想要查的key1 也放到索引里面
联合索引、最左匹配原则
如(key1,key2,key3),相当于创建了(key1)、(key1,key2)和(key1,key2,key3)三个索引,这就是最左匹配原则
数据库索引相关面试题
1.为什么用自增列作为主键
1.如果我们定义了主键,那么innodb会选择主键作为聚集索引
2.如果没有定义,那么innoDB会选择一个不含NULL的唯一索引作为主键索引
3.如果没有唯一索引,innoDB会选择内置的ROWID作为隐含的聚集索引
4.如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,如果满了会开辟新一页
5.如果不使用自增主键,每次插入到顺序都是随机的,MySQL不得不为了将新记录插到合适位置而移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增加了很多开销,同时频繁的移动、分页操作造成了大量的碎片