开发者学堂课程【数据库核心概念:索引(三)】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/63/detail/1143
索引(三)
MySQL 索引结构
主要有四种:
Btree 索引,Hash 索引,full-text 全文索引,R-Tree 索引;主要学习与开发相关的Btree 索引,其余三个知道名字即可,随着转型与深入其余的索引可以根据需求酌情升华与提高。
Btree 索引,索引原理:
模型中左边是表格即真实的数据右边是树,数据越来越多表格增长也越来越高,同理树越来越高查找的层次越来越多,能用3此找到就不多查找一次因为每查找一次就是一次磁盘 io,树的广度越大。
在数据库中物理存储上有单位:
段,区,块(类似于重量单位克,千克,吨)是一种衡量单位,上面课程中讲过 MySQL 逻辑架构分为4层,最底层是存储层即数据存储在磁盘上或磁柜上(硬盘实际是一个圆盘我们所看到的磁盘是经过封装的,有磁盘,磁道,壁柱,指针:进行寻道寻址;数据写在磁道上,根据检索条件从不同的磁道上查找相应的数据内容一串的读取,是一个存储单位)Java 是面向对象编程即一切即对象,无非是静态属性,针对属性可以做那些操作,动态的方法描述,实例变量与实例方法为类,封装一个单元,发布后进行调用。可以近似理解磁盘段,区,块;那以段的那个区域的那一小块存储了数据,磁盘存储是一块一块的类似于豆腐块。
图中有三种颜色,第一种浅蓝色的为磁盘块,第二种深蓝色的,最后一种是黄色:各种指针。
业务诉求:查询的数据在磁盘上,先把数据检索出来,然后建立Btree,浅蓝色的称之为磁盘块可以看到每个磁盘块包含几个数据项(深蓝色所示)和指针(黄色所示),在查找时一定需要一个参考,磁盘块1相当于树的根,中间的相当于树的枝干,第三层相当于树的叶子。
如果需要查找数字29,磁盘块1包含数据项17和35,包含指针 P1、P2、P3。
P1 表示小于17的磁盘块,P2 表示在17和35之间的磁盘块,P3 表示大于35的磁盘块。真实的数据存在于叶子节点即3、5、9、10、13、15、28、29、36、60、75、79、90、99。
非叶子节点不存储真实的数据,只存储指引搜索方向的数据项,如17、35并不真实存在于数据表中类似于中药中的药引是一个参考值。查找29,29大于17小于35,最开始都是从磁块1进行加载,下一步的指向是依据指针 P1、P2、P3;由于29大于17小于35,所以指向 p2,P2 的引用有指向了磁块3并不是按顺序从磁块2开始加载,第二次io读出磁块3,29在27与30之间有指向引用P2,P2的引用有指向了磁块8,磁块8中存储了29。根据树的高度自顶而下逐步检索直到找到29,只查找了三层没有进行全部扫描。
如果要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存,(注意:非叶子节点不存储真实数据如17、35并不真实存在于数据)此时发生一次 IO,在内存中用二分查找确定29在17和35定间,锁定磁盘块1的 P2指针,内存时间因为非常短(相比磁盘的1O)可以忽略不计,通过磁盘块1的 P2指针的磁盘地址把磁盘块3由磁盘加载到内存发生第二次 IO,29在26和30之间,锁定磁盘块3的 P2指针,通过指针加载磁盘块8到内存,发生第三次 IO,同时内存中做二分查找找到29,结束查询,总计三次 IO。
说明B树的高度为3,树最好数据横向扩充,高度越矮越好。真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次 IO,性能提高将是巨大的(类比百万此的全文扫描),如果没有索引,每个数据项都要发生一次口,那么总共需要百万次的1口,显然成本非常非常高。
在什么情况下建立索引
在什么情况下建立索引:
(1).主键自动建立唯一索引
(2).频繁作为查询条件的字段应该创建索引;例如银行系统的银行账号,电信系统的手机号,所做积分项目中的微信号应该作为创建索引
(3).查询中与其它表关联的字段,外键关系建立索引;例如员工与部门表中 deptid
(4).频繁更新的字段不适合创建索引。因为每次更新不单单是更新了记录还会更新索引
(5).Where 条件里用不到的字段不创建索引;比如 where 中按照银行卡号查询,区分最多的是银行卡号而且需要快速查找;即能满足查找又能满足业务的建立索引其他尽量不建索引
(6).单键/组合索引的选择问题即单值索引还是复合索引,选择复合索引。
(7).查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度。
索引做两件事:检索和排序。
假设给系统建立三个字段的复合索引,第一个字段为 name 第二个字段为 age 第三字段叫 Emile 地址,系统希望按建立索引顺序进行按序查询,排序(order by)时也希望按此顺序进行排序。查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度。即建立索引不但需要考虑快速查询还要考虑是否与 order by 的排序诉求‘撞车’。
(8).查询中统计或者分组字段。分组 group by,但分组前提是必须排序即 group by 也与索引相关同样需要满足符合的要求。
在什么情况下不建立索引:
(1).表记录太少。比如数据库中就几百条数据,那么使用建与不建没啥区别,并不会影响效率。如果数据达到百万条,MySQL 在三百万左右效率逐渐下降虽然官方上说可以支撑五百万到八百万条数据,但实际使用在三百万条数据时就开始优化。
(2).经常增删改的表,不建索引。因为索引虽然提高了查询速度,但同时却会降低更新表的速度,如对表进行 INSERT、UPDATE 和 DELETE。因为更新表时,MySQL 不仅要保存数据,还要保存一下索引文件。
(3).数据重复且分布平均的表字段,不要建立索引。因此应该只为最经常查询和最经常排序的数据列建立索引。
注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。假设在班级上有一个国籍字段,同学的国籍都是中国是一个固定且唯一的值,使用此字段建立索引没有任何效果。
性别只有两种:男和女;此字段差异率不高使用这种字段建立索引没有意义。
小公式:假如一个表有10万行记录,有一个字段 A 只有 T 和 F 两种值,且每个值的分布概率大约为50%,那么对这种表A字段建索引一般不会提高数据库的查询速度。对银行卡号建立索引,因为银行卡号没有重复的值。
索引的选择性是指索引列中不同值的数目与表中记录数的比。如果一个表中有2000条记录,表索列有1980个不同的值,b 那么这个索引的选择性就是1980/2000=0.99.一个索引的选择性越接近于1,这个索引的效率就越高。也就是说重复且分布平均的字段建立索引效果不大。