从程序员的角度深刻理解MySQL

数据库基本原理

clipboard.png

第一,数据库的组成:存储 + 实例程序员

没必要多说,数据固然须要存储;存储了还不够,显然须要提供程序对存储的操做进行封装,对外提供增删改查的API,即实例。数据库

一个存储,能够对应多个实例,这将提升这个存储的负载能力以及高可用;多个存储能够分布在不一样的机房、地域,将实现容灾。性能优化

第二,按Block or Page读取数据数据结构

用大腿想也知道,数据库不可能按行读取数据(Why? ? ^_^)。实质上,数据库,如Oracle/MySQL,都是基于固定大小(好比16K)的物理块(Block or Page,我这里就不区分统一称为Block)来实现调度和管理的。要知道Block是数据库的概念,如何对应到文件系统呢?显然须要指出“这个Block的地址在哪里”,当查找到地址后,读取固定大小的数据就至关于完成了Block的读取了。架构

数据库很聪明的,它不会仅仅只读取须要读取的Block,它还会替咱们把附近的Block块都读取加载至内存。实际上,这是为了减小IO次数,提升命中率。事实上,一个Block块的附近Block也是热点数据,这种处理方式颇有必要!并发

第三,磁盘IO是数据库的性能瓶颈分布式

毫无疑问,数据在磁盘上,少不了磁盘IO。什么磁头旋转,定位磁道,寻址的过程,就不说了,咱们是程序员,也管不了这些。可是这个过程确实是很是耗时的,和内存读取不是一个数量级,因此后来出现了不少方式来减小IO,提高数据库性能。函数

好比,增长内存,让数据库把数据更多的加载至内存。内存虽好,但也不能滥用,为何这么说呢?假设数据库中有100G数据,若是都加载至内存,也就说数据库要管理100G磁盘数据+100G内存数据,你说累不累?(数据库要处理磁盘和内存的映射关系,数据的同步,还要对内存数据进行清理,若是涉及数据库事务,又是一系列复杂操做......)不过这里须要指出的是,为了加快内存查找速度,数据库通常对内存进行HASH存放。微服务

好比,利用索引,索引相比内存,是一个性价比很是高的东西,后文详细介绍MySQL的索引原理。高并发

好比,利用性能更好的磁盘...(和我们就不要紧呢)

第四,提出一些问题思考下:

为何咱们说利用delete删除一个表的数据较trancate一个表要慢?

【一个按行查找删除,多费劲;一个基于Block的体系结构删除】

为何咱们说要小表驱动大表?

【小表驱动大表会快?什么鬼?MN和NM不是同样的么?有鬼的地方,就有索引!】

探索MySQL索引背后的原理

对于绝大数的应用系统,读写比例在10:1,甚至100:1,并且insert/update很难出现性能问题,遇到最多的,最棘手的就是select了,select优化是重中之重,显然少不了索引!

提及MySQL的索引,咱们会冒出不少这些东西:BTree索引/B+Tree索引/Hash索引/汇集索引/非汇集索引...这么多,晕头!

索引究竟是什么,想解决什么问题?

老生常谈了,官网说MySQL索引是一种数据结构,索引的目的就是为了提升查询效率。

说白了,不使用索引的话,磁盘IO次数比较多!要想减小磁盘IO次数,怎么办?

咱们想经过不断缩小想要获取的数据的范围来筛选出最终想要的结果,把每次查找数据的磁盘IO次数控制在一个很小的数量级,最好是常数数量级。

为了应对上述问题,B+Tree索引出来了!

Hello,B+Tree

在MySQL中,不一样存储引擎对索引的实现方式是不一样的,这里将重点分析MyISAM和Innodb。

clipboard.png

咱们知道对于MyISAM引擎而言,数据文件和索引文件是分离的。从图中也能够看出,经过索引查找到后,就获得了数据的物理地址,而后根据地址定位数据文件中的记录便可。这种方式也叫"非汇集索引"。

而对于Innodb引擎而言,数据文件自己是索引文件!通俗点说,叶子节点上,MyISAM存储的是记录的物理地址,而Innodb上存储的是数据内容,这种方式即"汇集索引"。

另一点须要注意的是,对于Innodb而言,主键索引中叶子节点存储的是数据内容,而普通索引的叶子节点中存储的是主键值!也就是说,对于Innodb的普通索引字段查找,先经过普通索引的B+Tree查找到主键后,而后经过主键索引的B+Tree进行查找。从这里你能够看出,对于Innodb而言,主键的创建很是重要!

而对于MyISAM而言,主键索引和普通索引仅仅的区别在于主键只须要查找到一条记录便可中止,而普通索引容许重复,找到一条记录后须要继续查找,在结构上没有区别,如上图所示。

想利用索引,就得“干净”

什么叫“干净”?就是不要让索引参与计算!好比在索引上应用函数,极可能致使索引失效。为何呢?

其实不用想,B+Tree上存储的是数据,要比较的话,须要把全部的数据都应用上函数,显然成本太大。

想创建索引,看看区分度

索引虽然物美价廉,可是也别乱来。count(distinct col) / count(*)能够算一下col的区分度,显然对于主键而言,就是1。区分度过低的话,能够考虑下,是否还有必要创建索引呢?

Hash索引

这里并非要深刻分析Hash索引,而是要说明一下Hash的思想真是无处不在!

在MySQL的Memory存储引擎中,存在hash函数,给一个key,经过hash函数进行计算获得地址,因此一般状况下,hash索引查找,会很是快,O(1)的速度。可是也存在hash冲突,和HashMap同样,经过单链表的形式解决。

思考下,hash索引是否支持范围查询呢?

显然是不支持的,它只能给一个KEY去查找。就如同HashMap同样,查找key包含"zhangfengzhe"的,会很快么?

在此我向你们推荐一个架构学习交流群。交流学习群号:478030634 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

SQL优化神器:explain

SQL优化的场景不少,网上的技巧也不少,彻底记不住!

要想完全解决这个问题,我想只有把索引背后的数据结构和原理作适当的理解,遇到书写SQL或者SQL慢查询的时候,咱们有基础去分析,再利用好explain工具去验证,就应该问题不大呢。

explain查询的结果,能够告诉你哪些索引正在被使用,表是如何被扫描的等等。这里我将演示个Demo。

数据表student:

clipboard.png

注意复合索引(age,address)

clipboard.png

符合最左前缀匹配

clipboard.png

复合索引失效

OK,到这里,准备结束了,查询容易,优化不易,且写且珍惜!

相关文章
相关标签/搜索