一条SQL语句是如何执行的?

SQL语句执行的经过

从用户发起请求,到服务接口调用MySQL驱动,MySQL服务器执行完SQL语句返回结果中间发生了什么?首先放一张图来看整个过程使用到的各个组件,然后再对各个过程进行分析。

SQL语句执行链路

1. 连接过程

以Openresty服务器为例,Openresty是多进程+I/O多路复用结构(Nginx的I/O模型),可以支撑高的并发,一个Worker就是一个进程,一个进程可以处理多条请求。
我们知道当需要执行SQL语句时需要先于MySQL服务器建立连接,如果每个一个请求都建立一个连接,使用完再关闭连接,如果频繁的创建和销毁连接显然是不合理的,浪费系统资源造成性能下降,这时连接池就出现了。

连接池

连接池会维护多个(长)连接,一个SQL语句执行时分配一个连接,使用完不会销毁连接,而是放到空闲队列中等待下次使用,这样可以在高并发的场景大大减少创建、销毁连接带来的性能问题。

连接器

类似Web服务器通过连接池维护与数据库服务器的连接,MySQL的连接器提供了同样的功能,也维护了一个连接池,不同的是MySQL连接器同时还有权限验证的功能。

  • 修改密码不会影响已经建立的链接。
  • 连接完成后如果没有操作,改连接就会处于空闲状态,可以使用show processlist命令查看,如果长时间没有操作连接器会在到达超时时间后断开它。

长连接

长连接是客户端持续有请求,使用的是同一个连接,建立连接的过程通常是比较慢的,建议尽量使用长连接。但是长连接累计较多时可能会导致内存过大(内存管理在连接对象里),比系统强行kill,引起MySQL异常重启,可以使用以下两种方法解决:

  • 定期断开长连接。
  • 如果是MySQL5.7及以上的版本,可以在每次执行一个比较大的操作后执行mysql_reset_connection重新初始化连接资源(不会重新建立连接)。

2. 执行过程

查询缓存

如果是查询语句,而且开启了查询缓存,连接器拿到一个查询请求后,会先查看查询缓存是否有(之前执行过这条语句)。缓存key为sql语句,value是查询结果。

  • 不建议开启查询缓存,除非是基本不会变的数据表。因为只要对表有更新,该表上的所有查询缓存都会清空,导致查询命中率很低。

分析器

分析器的功能就是对SQL语句做词法分析和语法分析,解析这条语句要干什么,语法错误会返回错误提醒。

优化器

优化器是在表中有多个索引的时候决定使用哪个索引,或者有多表关联(join)的时候决定各个表的连接顺序。

执行器

通过分析器知道了要做什么,优化器知道了改怎么做,执行器就是真正的语句执行阶段。开始执行的时候要先判断对表是否有权限(在优化器之前也会做预检查)。执行器会调用存储引擎提供的接口进行读写操作。

3. 更新语句执行过程

查询语句是只读的,比较简单,经过一系列组件最终查询到结果返回。但是更新语句就相对复杂一些,涉及到两个日志模块:redo log和binlog。

redo log(重做日志)

如果每次更新都要刷盘,整个过程磁盘IO成本、查询成本都比较高,为了提升更新效率,InnoDB引擎提供了redo log(顺序写入速度很快)。

WAL(Write-Ahead Logging):先写日志,再写磁盘。当有一条记录需要更新的时候,InnoDB引擎会先将记录写入redo log并更新内存,这时候更新就算完成了,再需要的时候再将这个操作更新到磁盘里。

日志结构:redo log大小是固定的,比如配置一组4个文件,每个文件1G,
就可以记录总共4G的记录。从头开始写,写完后又回到开头循环写入。

crash-safe:故障安全,redo log除了能提高更新操作的效率,同时还保证了故障安全,在数据库异常时不会导致数据丢失。

binlog(归档日志)

MySQL最开始没有InnoDB引擎,binlog日志只用于归档和复制,只依靠binlog没有crash-safe能力。

  • redo log是InnoDB引擎独有的,属于存储层;binlog是MySQL提供的,属于server层
  • redo log是物理日志,记录在某个数据页上做了什么修改;binlog是逻辑日志,记录SQL语句的原始逻辑
  • redo log是循环写的,空间固定,用完会从头开始写;binlog是追加写的,一定大小后切换到下一个文件,不会覆盖

Buffer Pool缓冲池

InnoDB重要的内存结构,数据的操作都是在Buffer Pool中操作的,如果数据不在缓冲内存中,会先从磁盘中读取到数据页到缓冲池,然后再执行相关操作。

update执行过程

update T set k = k + 2 where id = '1' limit 1

  1. 执行器调引擎读接口找id=2这一行,如果数据页本来在内存就直接返回,否则先从磁盘load到内存中再返回。
  2. 然后执行器将k值加上2,得到新的一行数据,在调用引擎的写接口写入这行新数据。
  3. 引擎将这行数据更新到内存中,同时将更新操作记录到redo log,此时redo log处于prepare状态,然后告知执行器执行完成,可以提交事务。
  4. 执行器生成这个操作的binlog并写入磁盘。
  5. 执行器调用存储引擎的事务提交接口,引擎把刚写入redo log改为commit状态,更新完成。

两阶段提交

保证了crash-safe能力,如果不使用两阶段提交,使用binlog恢复数据库时会导致与原数据库状态不一致。

假如不使用两阶段提交,在写日志时机器发生故障:

  1. redo log写入(比如k,本来为0,执行更新后
    k = 2)后发生故障,binlog未写入。由于redo log写完之后即使系统崩溃,也会能将数据恢复,恢复后这一行数据k=2。但是binlog没写完就crash,binlog没有记录这条语句,如果使用binlog来恢复时会少一个事务,恢复后的k=0,原数据库k=2。
  2. binlog写入后发生故障,redo log未写入。redo log为写入,崩溃后这个事务无效,k=0。但是binlog已经记录了更新语句,之后恢复时会多出一个事务,恢复后k=2,原数据库k=0。

总结

  1. MySQL连接器使用连接池维护连接,并进行检查权限,接收一个SQL语句
  2. 然后通过分析器、优化器知道如何执行SQL语句
  3. 通过执行器与存储引擎交互,完成数据的读写。
  4. 数据更新同时会写入两个重要的日志文件:redo log和binlog,并通过两阶段提交保证了crash-safe能力。

参考资料
【码农有道】详解一条 SQL 的执行过程
【极客时间】MySQL实战45讲01、02讲

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

推荐阅读更多精彩内容