深入数据库原理

前言

最近想将自己对计算机基础知识的理解及思考整理成文章记录下来。这是一篇关于数据库的理论基础,希望对在找工作或准备面试的同学能有所帮助。话不多说,全文干货。

数据库原理概述

数据库从宏观上来讲,分为关系型数据库和非关系型数据库两种。所谓的关系型数据库最典型的数据结构是表,其结构是由二维表及其之间的联系所组成的一个数据组织,可以通过SQL的方式进行单表、多表之间的查询。而非关系型数据库,其最大的特点就是可以将数据用结构化的方式存储,可以存储基础的key&value之外,可以存储图片、文档等,且IO性能奇高。今天我们以关系型数据库中的明星产品Mysql来分析一下数据库的底层原理。

数据库的基本组成及sql执行流程

数据库的逻辑结构

要了解数据库,先从它的逻辑结构入手。如上图,数据库的逻辑构成可以分为四个部分
(1)第一层,连接控制,主要是不同客户端的连接、授权。比如客户端通过JDBC或ODBC连接数据库,并发送SQL请求,数据库会更先判断用户权限,权限通过则会执行连接。除此之外,该模块还应记住客户端的连接状态,以便返回数据或控制信息
(2)第二层,查询解析,主要是处理客户端的发送的sql,解析判断语句是否正确。
(3)第三层,查询优化器,处理客户端的sql语句,系统会计算语句的执行成本并解析优化。这也是数据库中最奇妙的一块,可能会带来一些奇怪的事情,举个例子,客户端编写了一条使用了索引的sql且索引使用符合规范,但是通过explain查看执行情况时,发现执行过程没有走索引,这种情况就有可能时查询优化器通过成本计算之后发现该语句不走索引比走索引成本更优。这一块逻辑相当复杂,建议有兴趣的同学可以深入研究。
(4)第四层,存储引擎,真实的执行sql语句。

所以我们不难总结出:一个sql的执行流程如下:
当客户端传入一条sql后,数据库首先会进行系统鉴权,如果鉴权成功则会对此sql进行解析分析。查询优化器会对解析完成的sql进行查询优化,计算成本,判断是否需要走索引。最后才会进入到存储引擎中进行磁盘IO,将具体数据加载进内存。

数据库与磁盘的交互原理

上文中,我们提到了sql进入存储引擎之后会进行磁盘IO,接下来我们展开聊一聊数据是如何从磁盘中进行读取的。
从本质上来讲,我们的数据库中的数据都存放在数据表空间之中。数据表空间的结构如下图所示。
数据表空间
简单理解,数据表空间可以分为多个段,段里面会有多个不连续的区,每个区中会有多个页,而我们的数据则是按照规律存放在一个一个页中。值得一提的是,数据库中每个页的容量为16k,一个区中包含有64个页,所以一个区的大小刚好为1M。

局部性原理

为了更好的理解数据库与磁盘的交互原理,有一个原理我们无法忽视,就是所谓的局部性原理。这个原理的意思是说,我们每一次进行磁盘IO, 发生IO的容量是一定的,大小都是一个页。
所以我们可以简单分析出,数据库在和磁盘进行IO的过程中,每次加载进内存的大小都是一页,也就是16K。

一条SQL的查询流程

我们知道了数据是按页进行加载到内存的,那么问题来了,一个sql到底是如何读取出数据的呢。
在我们常用的sql理解中,数据是以行的形式读取出来的,其实不然,通过上述的结构,我们可以了解到,单次从磁盘读取单位是页,而不是行,也就是说,你即便只读取一行记录,从磁盘中也是会读取一页的。
我们以Innodb引擎为例介绍一下一个sql是如何进行查询的。(mysql数据库支持多种引擎,这里简单介绍一下,后面会详细介绍)
Innodb
innodb底层数据的结构是B+树,B+树中每一个节点大小都是一页。故此整体的查询逻辑如下:
从根节点开始向下查询,在目录页中找到sql中对应的Key, 根据Key来找到该key存放的下一子节点地址,则将该子节点从磁盘中加载进内存。页里面还有一个类似于有序数组,被称为的数据结构,在里面可以用二分查找来提高查找效率。

哈哈!有点懵?不要紧,后面给大家详细介绍一下所谓的引擎、索引的具体数据结构及其原理。

索引及其数据结构

之前看了一些文章,有朋友说可以把索引理解为是目录,我认为有一点不太准确。我认为,从本质上来讲,索引是一种特殊的数据结构,它的作用就是将数据由无序变为有序,便于存储及查询。当然,不是所有的数据加入索引之后都会变得快速,这个具体情况具体分析,这里不做叙述。接下来给大家比较一下几种常见的索引结构及其优缺点。

· hash索引

hash索引的特点就是快,非常之快,因为其结构就是简单的Key-value。但它的缺点也很突出,不支持顺序及范围查找,但是对于数据库而言,范围查找只是基本要求,很明显hash索引不适合用来作为数据库的索引结构。

· B树索引

b树是多路查找树。相较于二叉树结构,它由一个节点出发会有多条支路,且每一个节点里会有多个子节点,每个子节点都存放有真实数据,相较于红黑树、二叉平衡树来讲极大的减少了磁盘IO次数。

· B+树索引(主流数据库索引结构)

B+树是B树的升级版,主要的区别主要有两个。
其一。子节点只存放索引,而不存放真实数据。前文提到,数据库每次IO大小是一页(16K), 如果只存放索引,每一次IO则可以加载更多的索引,能更快的找到目标数据,较少IO次数。
其二。B树如果需要做顺序查找或范围查找,只能通过中序遍历、后续遍历等方式。而B+树在B树基础之上在叶子节点中加入了双向链表,如此一来,当想要进行顺序或范围查找时,速度更快,效率更高。
故此,B+树时目前主流的数据库索引结构。

mysql中的数据引擎

其实,在mysql中曾出现过多种数据引擎,如Innodb、myIsam、memory等等。目前主流的主要用到的innodb、myIsam两种。

MyIsam与Innodb相同点:底层都是B+树
MyIsam与Innodb不同点:
区别1: MyIsam不支持事务、Inndb支持事务(核心区别)
区别2: MyIsam只支持表级锁、Inndb支持表、行级锁
区别3: MyIsam主键索引是非聚集索引、Inndb主键索引是聚集索引
区别3: MyIsam主要场景在读多写少(如CMS管理系统等),在并发场景中表现不好、在并发场景中普遍选用Innodb

解释一下聚集索引和非聚集索引:
MyIsam的主键索引实现:
myisam
上图是一个MyISAM表的主索引(Primary key)示意。可以看出MyISAM的索引文件仅仅保存数据记录的地址。

再来看Innodb的主键索引结构
innodb
上图是InnoDB主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引。

综上,所谓聚集索引和非聚集索引的主要区别在于:
数据文件和索引文件是否一起保存
聚集索引的好处的就是,可以通过直接查找到相应数据,非聚集索引则需要通过地址在读取数据文件。

回表

如上图所示,主键索引中才存放有真实数据或指向真实数据的地址。而非主键索引只会存放主键索引的地址。如果在查询的过程中,走了非主键索引则需要通过回表来再次走主键索引才能找到真实数据地址。

深入数据库事务

前文提到Innodb引擎是支持事务的。
所谓的事务可以理解为一批一起执行的sql语句,这些语句要么都执行成功,要么都不成功,如果不成功,会执行数据回滚。也就是我们常说的事务具有ACID特性,(A)原子性、(C)一致性、(I)隔离性、(D)持久性

这些特性底层是如何实现的,咱们分别来看。
A - Atomicity : 一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作
实现原理: 通过UndoLog
Innodb在每次进行数据修改时,都会写一些log, 如RedoLog(重做日志)记录下当前执行的语句,用来备份和回溯; UndoLog : 记录上操作语句的逆向操作语句,并且在日志生成之后会先行持久化到磁盘之上,比数据持久化早一些。而回滚操作,就是靠着undo log日志中记载的操作变化进行逆向操作,添加数据变为删除,删除数据变为添加,修改数据变为修改成日志上记载的数据。当系统发生错误或者执行rollback操作时需要根据undo log 进行回滚, 以此来保证原子性。

I - Isolation: 事务的隔离性是指在并发环境中,并发的事务时相互隔离的,一个事务的执行不能不被其他事务干扰。不同的事务并发操作相同的数据时,每个事务都有各自完成的数据空间,即一个事务内部的操作及使用的数据对其他并发事务时隔离的,并发执行的各个事务之间不能相互干扰。
实现原理:MVCC(多版本控制)
数据库有四种隔离级别:RU 、RC、RR、串行化
MVCC主要是在RC和RR的隔离级别存在,只是使用的方式不同。
在RC时,是在每一次Select时都生成一个版本,其他事务有可能查到最新版本数据(不可重复读)。
在RR时,是在事务入口时生成了一个大版本,每次select都是读那个大版本数据。

D - durability : 一旦事务提交,那么它对数据库中的对应数据的状态的变更就会永久保存到数据库中。–即使发生系统崩溃或机器宕机等故障,只要数据库能够重新启动,一定能够将其恢复到事务成功结束的状态。
实现原理:Buffer & RedoLog
事务一旦提交之后,所做的修改将永久的保存在数据库里面,即便数据库出现crash的现象也不会丢失相应的数据。Innodb内部会有缓存Buffer并且会定时持久化。但当出现电脑死机或者断电的轻缓,就有可能丢失相应数据,而这时就是通过redo log来保证持久性

C- 一致性,通过以上三种方式来保证数据一致性。

浅析数据库调优方法论

如何识别慢Sql

如何识别慢Sql
查看慢SQL是否启用,查看命令:show variables like ‘log_slow_queries’; 如果结果为ON则是开启了,如果为OFF则表示禁用了。
开启慢查询命令:set global log_slow_queries = on;
查看慢查询参数,即设置超过多少秒的查询归为了慢查询。参数为:long_query_time,查询命令: show global variables like ‘long_query_time’;
mysql默认时间为10秒,即10秒及以上的查询被归为了慢查询。我们的实际项目中根本就不可能这么包容你,所以得提供查询效率优化sql,让程序更快的执行。
查看慢查询存放日志,命令: show variables like ‘slow_query_log_file’;去相应目录下查看即可。

Sql慢的原因

偶尔慢

如果是偶尔慢,可能有几种原因
 1. 刷脏页,占用了大量CPU、IO资源
		redoLog写满了,需要持久化到硬盘会很占资源
 2. 数据被加锁了、被别人占用(show processlist)

一直慢

该问题非常复杂,有几种原因,仅作参考
1. Sql本身问题,没有走索引,程序编写问题,需要符合最左前缀原则等
2. 数据库的原因:
	数据量太大,一个select可能需要很久,需要考虑分库分表的策略。

如何调优

参看链接: 深入慢sql优化.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值