【修真院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、使用了查询语句后,引擎检测使用了索引,然后会将值转换成哈希码,找到对应的索引中的哈希码,最后取出数据对比,以确保是要查找的行

例子:现有如下一个表


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

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


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

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


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

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

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

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

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

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

限制:

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

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

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

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

二叉树


一个简单的二叉树结构<br/>

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

然后指向E,最后指向H

一个简单的二叉树结构

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

然后指向E,最后指向H

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

如图是一个3阶B-Tree


系统从磁盘读取数据到内存时是以磁盘块(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


假设现在有如图这样一个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的聚集索引

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

聚集索引中的索引结构


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

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

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

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

非聚集索引结构


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

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

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

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.更多讨论

鸣谢

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容