【修真院JAVA小课堂】什么是DB的索引,多大的数据量下建索引会有性能的差别,什么样的情况下该对字段建索引?

1.背景介绍

1、索引是什么

索引是对数据库表中一个或多个列的值进行排序的结构

2、索引可以做什么

加快检索表中数据,亦即能协助信息搜索者尽快的找到符合限制条件的记录ID的辅助数据结构

2.知识刨析

索引分类:

普通索引:仅加速查询

唯一索引:加速查询 + 列值唯一(可以有null)

主键索引:加速查询 + 列值唯一(不可以有null)+ 表中只有一个

组合索引:多列值组成一个索引,专门用于组合搜索,其效率大于同时使用多条单列索引

全文索引:对文本的内容进行分词,进行搜索

索引方式:

Hash

B-Tree

B+Tree

RTree

建索引的几点原则

1.选择唯一性索引

唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录。例如,学生表中学号是具有唯一性的字段。为该字段建立唯一性索引可以很快的确定某个学生的信息。如果使用姓名的话,可能存在同名现象,从而降低查询速度。

2、限制索引的数目

索引的数目不是越多越好。每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。修改表时,对索引的重构和更新很麻烦。越多的索引,会使更新表变得很浪费时间。

3、尽量使用数据量少的索引

如果索引的值很长,那么查询的速度会受到影响。例如,对一个CHAR(100)类型的字段进行全文检索需要的时间肯定要比对CHAR(10)类型的字段需要的时间要多。

4、尽量使用前缀来索引

如果索引字段的值很长,最好使用值的前缀来索引。例如,TEXT和BLOG类型的字段,进行全文检索会很浪费时间。如果只检索字段的前面的若干个字符,这样可以提高检索速度。

5、删除不再使用或者很少使用的索引

表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再需要。数据库管理员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响。

6、最左前缀匹配原则,非常重要的原则。

mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a 1=”” and=”” b=”2” c=”“> 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。

3.常见问题

1、索引是怎样加快效率的?

在没有索引的情况下,数据库查找数据的时候会进行全盘扫描来寻找需要的数据,而索引将经常需要查询的数据单独建立了有序的结构,从而提高了效率

2、不同引擎有什么区别?

没有最好的引擎,只有最适合的引擎。

ISAM:读取操作的速度很快,不支持事务处理,不能在表损坏后恢复数据。

MyISAM:读取操作更快,不支持事务,不能在表损坏后恢复数据。

InnoDB:慢很多,但是支持事务处理和外来键。

4.解决方案

确定需求后在决定引擎

MyISAM:

(1)做很多count 的计算;

(2)插入不频繁,查询非常频繁;

(3)没有事务。

InnoDB:

(1)可靠性要求比较高,或者要求事务;

(2)表更新和查询都相当的频繁,并且表锁定的机会比较大的情况指定数据引擎的创建

5.编码实战

6.扩展思考

1、Hash(类似HashMap)

1、使用特定的哈希函数将索引列中的值生成哈希码 hashcode ,不同的值生成的哈希码不一样

2、哈希索引将所有的哈希码和指向每个数据行的指针保存到索引中

3、如果生成的哈希码是一样的,则在那一行生成链表

4、使用了查询语句后,引擎检测使用了索引,然后会将值转换成哈希码,找到对应的索引中的哈希码,最后取出数据对比,以确保是要查找的行

例子:现有如下一个表


【修真院JAVA小课堂】什么是DB的索引,多大的数据量下建索引会有性能的差别,什么样的情况下该对字段建索引?_第1张图片

有7为学生及相应的得分,其中有3位重名

在姓名列建立Hash索引,假设有这样的哈希函数F(),他返回这样的值


【修真院JAVA小课堂】什么是DB的索引,多大的数据量下建索引会有性能的差别,什么样的情况下该对字段建索引?_第2张图片

(都是假设数据,并非真实数据)

那么建立的Hash索引数据结构如下


【修真院JAVA小课堂】什么是DB的索引,多大的数据量下建索引会有性能的差别,什么样的情况下该对字段建索引?_第3张图片

每个槽的编号是排序的,但是数据行不是

相同的姓名(Addision)生成的哈希码是相同的,将会以链表方式解决

假如现在要查询 select score from table where name = 'Fred'

MySQL会先计算 'Fred' 的哈希值,即 f( ' Fred ' )=8464

然后使用该值寻找对应的槽,然后就找到对应的指针“指向第4行的指针”

最后会到第4行比对name是否是 ' Fred ' ,确保是要查找的行,输出:60

限制:

1、哈希索引不存储字段值,不能用来做覆盖索引

2、哈希索引数据不是按照索引值排序的,无法用于排序

3、哈希索引是按照索引列全部内容进行计算哈希值的,所以不支持范围查找

4、哈希冲突多的话,效率会受影响,不稳定,存储引擎必须遍历链表中的所有行指针,逐行对比知道找到相应的行。同样的删除也会受影响

二叉树


【修真院JAVA小课堂】什么是DB的索引,多大的数据量下建索引会有性能的差别,什么样的情况下该对字段建索引?_第4张图片

一个简单的二叉树结构

以此为例,假如找H,那么要先找到F(代表该二叉树)

然后指向E,最后指向H

一个简单的二叉树结构

以此为例,假如找H,那么要先找到F(代表该二叉树)

然后指向E,最后指向H

2、B-Tree平衡多路二叉树

如图是一个3阶B-Tree


【修真院JAVA小课堂】什么是DB的索引,多大的数据量下建索引会有性能的差别,什么样的情况下该对字段建索引?_第5张图片

系统从磁盘读取数据到内存时是以磁盘块(block)为基本单位的,位于同一个磁盘块中的数据会被一次性读取出来,而不是需要什么取什么。

例子

假设现在有如图这样一个B-Tree索引,找键10携带的数据

1、根据根节点找到磁盘块1,读入内存。【I/O操作第1次】

2、比较关键字10在小于17区间,找到磁盘块1的指针P1。

3、根据P1指针找到磁盘块2,读入内存。【I/O操作第2次】

4、比较关键字10在区间(8,12),找到磁盘块2的指针P2。

5、根据P2指针找到磁盘块6,读入内存。【I/O操作第3次】

6、在磁盘块6中的关键字列表中找到关键字10。

分析上面过程,发现需要3次磁盘I/O操作,和3次内存查找操作由于内存中的关键字是一个有序表结构,

可以利用二分法查找提高效率。而3次磁盘I/O操作是影响整个B-Tree查找效率的决定因素,

但是该表中查询数据最多只使用3次I/O操作,但是相对于普通二叉树,和平衡二叉树,B-Tree缩减了节点个数,

使每次磁盘I/O取到内存的数据都发挥了作用,从而提高了查询效率。

3、B+Tree

只有叶子记录关键字记录的指正,非叶子节点只进行数据索引,所有数据地址必须要到叶子节点才能获取到,所以每次数据查询的次数都一样。

例子

如图是一个3阶B+Tree


【修真院JAVA小课堂】什么是DB的索引,多大的数据量下建索引会有性能的差别,什么样的情况下该对字段建索引?_第6张图片

假设现在有如图这样一个B+Tree索引,找键63携带的数据

1、根据根节点找到磁盘块,读入内存。【磁盘I/O操作第1次】

2、比较关键字63在区间[28,65),找到磁盘块的指针P2。

3、根据P2指针找到磁盘块,读入内存。【磁盘I/O操作第2次】

4、比较关键字63在区间[56,65),找到磁盘块的指针P3。

5、根据P3指针找到磁盘块,读入内存。【磁盘I/O操作第3次】

6、在磁盘块中的关键字列表中找到关键字63。

分析上面过程,发现不管查找哪个数据都需要3次I/O操作,

所以查询速度稳定,查询速度非常接近二分法。

另外B+Tree中非叶子节点不需要保存关键字记录的指针,

每个节点能保存的关键字大大增加,所以B+Tree比B-Tree更有效率、更稳定。

4、聚集索引(InnoDB引擎)

聚集索引的主索引的叶子节点存储的就是数据本身,辅助索引的叶子节点存储的是对应数据的主键键值。

在指定主键时会建立主索引

每个主键都携带着数据行,找到主键即找到了数据行

如果没有指定主键,系统内部会自动生成一个“行id”,

但是无法操作该数据,然后生成一个包含该id的聚集索引

所以系统中总会有且仅有一个聚集索引。

聚集索引中的索引结构


【修真院JAVA小课堂】什么是DB的索引,多大的数据量下建索引会有性能的差别,什么样的情况下该对字段建索引?_第7张图片

左边是主索引,右边是辅助索引

聚簇索引的数据是根据主键的顺序保存。

如果只需要查找索引的列,就尽量不要加入其它的列,这样会提高查询效率。

5、非聚集索引(MyISAM引擎)

非聚集索引结构


【修真院JAVA小课堂】什么是DB的索引,多大的数据量下建索引会有性能的差别,什么样的情况下该对字段建索引?_第8张图片

非聚集索引中的主索引和辅助索引几乎是一样的,主索引不允许重复和空值,他们的叶子都存储着键值对应的数据的物理地址

所以非聚集索引中的索引和数据是分开存储的

非聚簇索引中的数据是根据数据的插入顺序保存。

7.参考文献

1. 百度百科:数据库索引:https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B4%A2%E5%BC%95/8751686?fr=aladdin

2.How does InnoDB behave without a Primary Key?:https://blog.jcole.us/2013/05/02/how-does-innodb-behave-without-a-primary-key/

3.从Mysql源代码角度分析一句简单sql的查询过程:https://blog.csdn.net/vipshop_fin_dev/article/details/79688717

4.BTree和B+Tree详解:"https://blog.csdn.net/chuixue24/article/details/80027689

5.为什么索引可以加速查询?:https://blog.csdn.net/tongdanping/article/details/79878302

6.哈希索引:https://blog.csdn.net/olizxq/article/details/82313489

7.btree索引和hash索引的区别:https://www.cnblogs.com/ziqiumeng/p/7680204.html

8.更多讨论

鸣谢

感谢观看,如有出错,恳请指正

你可能感兴趣的:(【修真院JAVA小课堂】什么是DB的索引,多大的数据量下建索引会有性能的差别,什么样的情况下该对字段建索引?)