0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

一条SQL更新语句的执行流程1

jf_78858299 来源:蝉沐风的码场 作者:蝉沐风 2023-03-03 10:02 次阅读

这是图解MySQL的第2篇文章,这篇文章会通过一条SQL更新语句的执行流程让大家清楚地明白:

  • 什么是InnoDB页?缓存页又是什么?为什么这么设计?
  • 什么是表空间?不同存储引擎的表在文件系统的底层表示上有什么区别?
  • Buffer Pool是什么?为什么需要?有哪些我们需要掌握的细节?
  • MySQL的三种日志文件redo日志、undo日志、binlog分别是什么?为什么需要这么多种类型的日志?

正文开始!


之前我们讲过了一条SQL查询语句是怎么去执行的,那么插入(INSERT)、更新(UPDATE)和删除(DELETE)操作的流程又是什么样子呢?

其实对于MySQL而言,只有两种通常意义的操作,一种是Query(查询),另一种是Update(更新),后者包含了我们平常使用的INSERT、UPDATE和DELETE操作。

那么MySQL的更新流程和查询流程有什么区别呢?

其实基本的流程是一致的,也要经过 处理连接解析优化存储引擎几个步骤。主要区别在更新操作涉及到了MySQL更多的细节。

图片

注:我们接下来的所有描述,针对的都是InnoDB存储引擎,如果涉及到其他存储引擎,将会特殊说明

1. 一些需要知道的概念

对于MySQL任何存储引擎来说,数据都是存储在磁盘中的,存储引擎要操作数据,必须先把磁盘中的数据加载到内存中才可以。

那么问题来了,一次性从磁盘中加载多少数据到内存中合适呢?当获取记录时,InnoDB存储引擎需要一条条地把记录从磁盘中读取出来吗?

当然不行!我们知道磁盘的读写速度和内存读写速度差了几个数量级,如果我们需要读取的数据恰好运行在磁盘的不同位置,那就意味着会产生多次I/O操作。

因此,无论是操作系统也好,MySQL存储引擎也罢,都有一个预读取的概念。概念的依据便是统治计算机界的局部性原理。

空间局部性:如果当前数据是正在被使用的,那么与该数据空间地址临近的其他数据在未来有更大的可能性被使用到,因此可以优先加载到寄存器或主存中提高效率

就是当磁盘上的一块数据被读取的时候,我们干脆多读一点,而不是用多少读多少。

1.1 InnoDB页

InnoDB存储引擎将数据划分为若干个页,以页作为磁盘和内存之间交互的最小单位。InnoDB中页的大小默认为16KB。也就是默认情况下,一次最少从磁盘中读取16KB的数据到内存中,一次最少把内存中16KB的内容刷新到磁盘上。

图片

对于InnoDB存储引擎而言,所有的数据(存储用户数据的索引、各种元数据、系统数据)都是以页的形式进行存储的。

1.2 表空间

为了更好地管理页,MySQL又设计了「表空间」的概念。表空间又有很多类型,具体类型我们不需要知道,我们只需要知道,一个表空间可以划分成很多个InnoDB页,InnoDB表数据都存储在某个表空间的页中。

为了方便我们定位,MySQL贴心地为表空间设计了一个唯一标识——表空间ID(space ID)。同理,InnoDB页也有自己的唯一编号——页号(page number)。

因此,我们可以这么认为。给定表空间ID和页号以及页的偏移量,我们就可以定位到InnoDB页的某条记录,也就是数据库表的某条记录。

1.2.1 数据表在文件系统中的表示

为了更好地让大家理解这个抽象的概念,我创建了名为test的数据库,在其下分别创建了3张表t_user_innodbt_user_myisamt_user_memory,对应的存储引擎分别为InnoDBMyISAMMEMORY

进入MySQL的数据目录,找到test目录,看一下test数据库下所有表对应的本地文件目录

drwxr-x--- 2 mysql mysql  4096 Jan 26 09:28 .
drwxrwxrwt 6 mysql mysql  4096 Jan 26 09:24 ..
-rw-r----- 1 mysql mysql    67 Jan 26 09:24 db.opt
-rw-r----- 1 mysql mysql  8556 Jan 26 09:28 t_user_innodb.frm
-rw-r----- 1 mysql mysql 98304 Jan 26 09:28 t_user_innodb.ibd
-rw-r----- 1 mysql mysql  8556 Jan 26 09:27 t_user_memory.frm
-rw-r----- 1 mysql mysql     0 Jan 26 09:28 t_user_myisam.MYD
-rw-r----- 1 mysql mysql  1024 Jan 26 09:28 t_user_myisam.MYI
-rw-r----- 1 mysql mysql  8556 Jan 26 09:28 t_user_myisam.frm

1.2.2 InnoDB是如何存储表数据的

「表空间」是InnoDB存储引擎独有的概念。

我们看到t_user_innodb表在数据库对应的test目录下会生成以下两个文件

  • t_user_innodb.frm
  • t_user_innodb.ibd

其中,t_user_innodb.ibd就是t_user_innodb表对应的表空间在文件系统上的表示;t_user_innodb.frm用来描述表的结构,如表有哪些列,列的类型是什么等。

1.2.3 MyISAM是如何存储表数据的

和InnoDB不同,MyISAM没有表空间的概念,表的数据和索引全都直接存放在对应的数据库子目录下,可以看到t_user_myisam对应了三个文件

  • t_user_myisam.MYD
  • t_user_myisam.MYI
  • t_user_myisam.frm

其中,t_user_myisam.MYD表示表的数据文件,也就是我们实际看到的数据表的内容;t_user_myisam.MYI表示表的索引文件,为该表创建的索引都会存放在这个文件中;t_user_myisam.frm用来描述表的结构。

1.2.4 MEMORY是如何存储表数据的

MEMORY存储引擎对应的数据表只有一个描述表结构的文件t_user_memory.frm。

2. 缓冲池Buffer Pool

为了更好的利用局部性原理带给我们的优势,InnoDB在处理客户端请求时,如果需要访问某个页的数据,会把该数据所在的页的全部数据加载到内存中。哪怕是只需要访问一个页中的一条数据,也需要加载整个页。

从磁盘中加载数据到内存中的操作太昂贵了!有什么办法可以提高数据操作的效率呢?缓存!

为了缓存磁盘的页,InnoDB在MySQL服务器启动时会向操作系统申请一片连续的内存区域,这片内存区域就是 Buffer Pool

很容易理解,为了更好地缓存页数据,Buffer Pool对应的一片连续内存空间也被划分为若干个页,而且默认情况下,Buffer Pool页的大小和InnoDB页大小一样,都是16KB。为了区分两种不同的页,我们将Buffer Pool中的页面称为缓冲页。

图片

读取数据的时候,InnoDB先判断数据是否在Buffer Pool中,如果是,则直接读取数据进行操作,不用再次从磁盘加载;如果不是,则从磁盘加载到Buffer Pool中,然后读取数据进行操作。

修改数据的时候,也是将数据先写到Buffer Pool缓冲页中,而不是每次更新操作都直接写入磁盘。当缓冲页中的数据和磁盘文件不一致的时候,缓冲页被称为脏页。

那么脏页是什么时候被同步到磁盘呢?

InnoDB中有专门的后台线程每隔一段时间会把脏页的多个修改刷新到磁盘上,这个动作叫做「刷脏」。

3. redo日志

3.1 为什么需要redo日志

不定时刷脏又带来一个问题。如果脏页的数据还没有刷新到磁盘上,此时数据库突然宕机或重启,这些数据就会丢失。

首先想到的最简单粗暴的解决方案就是在事务提交之前,把该事务修改的所有页面都刷新到磁盘。但是上文说过,页是内存和磁盘交互的最小单位,如果只修改了1个字节,却要刷新16KB的数据到磁盘上,不得不说太浪费了,此路不通!

所以,必须要有一个持久化的措施。

为了解决这个问题,InnoDB把对所有页的更新操作(再强调一遍,包含INSERT、UPDATE、DELETE)专门写入一个日志文件。

当有未同步到磁盘中的数据时,数据库在启动的时候,会根据这个日志文件进行数据恢复。我们常说的关系型数据库的ACID特性中的D(持久性),就是通过这个日志来实现的。

这个日志文件就是大名鼎鼎的 redo日志

「re」在英文中的词根含义是“重新”,redo就是「重新做」的意思,顾名思义就是MySQL根据这个日志文件重新进行操作

图片

这就出现了一个有意思的问题,刷新磁盘和写redo日志都是进行磁盘操作,为什么不直接把数据刷新到磁盘中呢?

3.2 磁道寻址

我们需要稍微了解一下磁道寻址的过程。磁盘的构造如下图所示。

图片

每个硬盘都有若干个盘片,上图的硬盘有4个盘片。

每个盘片的盘面上有一圈圈的同心圆,叫做「磁道」。

从圆心向外画直线,可以将磁道划分为若干个弧段,每个磁道上一个弧段被称之为一个「扇区」(右上图白色部分)。数据是保存在扇区当中的,扇区是硬盘读写的最小单元,如果要读写数据,必须找到对应的扇区,这个过程叫做「寻址」。

3.2.1 随机I/O

如果我们需要的数据是随机分散在磁盘上不同盘片的不同扇区中,那么找到相应的数据需要等到磁臂旋转到指定的盘片然后继续寻找对应的扇区,才能找到我们所需要的一块数据,持续进行此过程直到找完所有数据,这个就是随机I/O,读取数据速度非常慢。

3.2.2 顺序I/O

假设我们已经找到了第一块数据,并且其他所需的数据就在这一块数据之后,那么就不需要重新寻址,可以依次拿到我们所需的数据,这个就叫顺序 I/O。

现在回答之前的问题。因为刷脏是随机I/O,而记录日志是顺序I/O(连续写的),顺序I/O效率更高,本质上是数据集中存储和分散存储的区别。因此先把修改写入日志文件,在保证了内存数据的安全性的情况下,可以延迟刷盘时机,进而提升系统吞吐。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 存储
    +关注

    关注

    13

    文章

    4259

    浏览量

    85652
  • buffer
    +关注

    关注

    2

    文章

    120

    浏览量

    30015
  • MySQL
    +关注

    关注

    1

    文章

    801

    浏览量

    26437
收藏 人收藏

    评论

    相关推荐

    STM8L执行一条语句大概需要几个时钟周期?

    STM8L执行一条语句大概需要几个时钟周期
    发表于 05-06 06:16

    DSP执行一条语句的时间

    CPU配置成150M。高频时钟75M。 那么执行一条语句的时间是多少呢
    发表于 10-15 11:28

    为什么要动态sql语句

    为什么要动态sql语句?因为动态sql语句能够提供些比较友好的机制1、可以使得
    发表于 12-20 06:00

    MySQL存储引擎完成更新语句执行的方法

    首先肯定是我们的系统通过个数据库连接发送到了MySQL上,然后肯定会经过SQL接口、解析器、优化器、执行器几个环节,解析SQL语句,生成
    的头像 发表于 10-21 10:40 2025次阅读
    MySQL存储引擎完成<b class='flag-5'>更新语句</b><b class='flag-5'>执行</b>的方法

    select语句和update语句分别是怎么执行

    样,但是具体的实现还是有区别的。 当然深入了解select和update的具体区别并不是只为了面试,当希望Mysql能够高效的执行的时候,最好的办法就是清楚的了解Mysql是如何执行查询的,只有更加全面的了解
    的头像 发表于 11-03 09:41 3519次阅读
    select<b class='flag-5'>语句</b>和update<b class='flag-5'>语句</b>分别是怎么<b class='flag-5'>执行</b>的

    一条SQL语句是怎么被执行

    直是想知道一条SQL语句是怎么被执行的,它执行的顺序是怎样的,然后查看总结各方资料,就有了下面
    的头像 发表于 09-12 09:44 1491次阅读
    <b class='flag-5'>一条</b><b class='flag-5'>SQL</b><b class='flag-5'>语句</b>是怎么被<b class='flag-5'>执行</b>的

    简述SQL更新语句执行流程1

    之前我们讲过了一条SQL查询语句是如何执行的,那么插入(INSERT)、更新(UPDATE)和删除(DELETE)操作的
    的头像 发表于 02-14 15:40 588次阅读
    简述<b class='flag-5'>SQL</b><b class='flag-5'>更新语句</b>的<b class='flag-5'>执行</b><b class='flag-5'>流程</b><b class='flag-5'>1</b>

    简述SQL更新语句执行流程2

    之前我们讲过了一条SQL查询语句是如何执行的,那么插入(INSERT)、更新(UPDATE)和删除(DELETE)操作的
    的头像 发表于 02-14 15:40 505次阅读
    简述<b class='flag-5'>SQL</b><b class='flag-5'>更新语句</b>的<b class='flag-5'>执行</b><b class='flag-5'>流程</b>2

    一条SQL查询语句是怎么去执行的?(上)

    MySQL是典型的`C/S架构`(客户端/服务器架构),客户端进程向服务端进程发送段文本(MySQL指令),服务器进程进行语句处理然后返回执行结果。
    的头像 发表于 03-03 09:58 358次阅读
    <b class='flag-5'>一条</b><b class='flag-5'>SQL</b>查询<b class='flag-5'>语句</b>是怎么去<b class='flag-5'>执行</b>的?(上)

    一条SQL查询语句是怎么去执行的?(中)

    MySQL是典型的`C/S架构`(客户端/服务器架构),客户端进程向服务端进程发送段文本(MySQL指令),服务器进程进行语句处理然后返回执行结果。
    的头像 发表于 03-03 09:58 431次阅读
    <b class='flag-5'>一条</b><b class='flag-5'>SQL</b>查询<b class='flag-5'>语句</b>是怎么去<b class='flag-5'>执行</b>的?(中)

    一条SQL查询语句是怎么去执行的?(下)

    MySQL是典型的`C/S架构`(客户端/服务器架构),客户端进程向服务端进程发送段文本(MySQL指令),服务器进程进行语句处理然后返回执行结果。
    的头像 发表于 03-03 09:58 375次阅读
    <b class='flag-5'>一条</b><b class='flag-5'>SQL</b>查询<b class='flag-5'>语句</b>是怎么去<b class='flag-5'>执行</b>的?(下)

    一条SQL更新语句执行流程2

    什么是InnoDB页?缓存页又是什么?为什么这么设计? * 什么是表空间?不同存储引擎的表在文件系统的底层表示上有什么区别? * Buffer Pool是什么?为什么需要?有哪些我们需要掌握的细节? * MySQL
    的头像 发表于 03-03 10:02 440次阅读
    <b class='flag-5'>一条</b><b class='flag-5'>SQL</b><b class='flag-5'>更新语句</b>的<b class='flag-5'>执行</b><b class='flag-5'>流程</b>2

    sql where条件的执行顺序

    。 在深入讨论WHERE条件的执行顺序之前,先回顾一下一SQL语句执行顺序。一条
    的头像 发表于 11-23 11:31 2136次阅读

    oracle执行sql查询语句的步骤是什么

    Oracle数据库是种常用的关系型数据库管理系统,具有强大的SQL查询功能。Oracle执行SQL查询语句的步骤包括编写
    的头像 发表于 12-06 10:49 890次阅读

    单片机中for语句的运用

    语句,它的基本结构如下: for (初始化语句; 条件表达式; 更新语句) {循环体;} for语句执行
    的头像 发表于 01-05 14:02 2163次阅读