【问题标题】:What happens inside MySQL when I execute an INSERT?当我执行 INSERT 时,MySQL 内部会发生什么?
【发布时间】:2018-02-05 14:54:54
【问题描述】:

假设我写了一个类似"INSERT INTO my_table (a,b) VALUES (1,2)" 的查询。
从客户端传递查询到它保存在磁盘上,MySQL 内部发生了什么。

喜欢:

-> What all innodb objects(filesystem buffers/logs) affected? 
-> What're the step the data has to pass through till it reaches on table space?

换句话说,数据库写入的解剖。

例如:

-> query being parsed by the parser
-> correct data page be loaded to innodb_buffer_pool
-> data being changed(dirty pages), and changes are logged to redo log buffer
-> entry on undo logs(rollback segment)
-> on commit, redo log buffer flushed to redo logfile
-> binary logging happens(if enabled)
-> dirty pages write to double write buffer
-> Finally it flushed to disk.

我相信人们有更好的方法/答案来解释这个序列。

【问题讨论】:

标签: mysql sql sql-insert


【解决方案1】:

这是假设 InnoDB,而不是任何其他引擎...

你有一些基础知识。这里还有一些。

-> Query received by Server
-> query being parsed by the parser
-> "open" table (if not already open)
-> check for "strict mode" errors
-> Hand off the query from "Handler" to "Engine".  (The rest assumes `ENGINE=InnoDB`)
-> If part of a transaction, ...
-> If autocommitting, ...
-> If `AUTO_INCREMENT, ...
-> If `INSERT` included `PRIMARY KEY` columns, ...
-> If neither of above, create hidden AI value, ...
-> Execute `BEFORE TRIGGERs`, if any
-> Given the PK, drill down the BTree to find the location.
-> Check for Duplicate Key -- PK and any relevant UNIQUE keys.
-> obtain eXclusive lock on the row -- (maybe gap lock?)
-> correct data page be loaded to innodb_buffer_pool (if not already cached)
-> If adding this row would overflow the block, "split" the block
-> Mark block(s) "dirty" (so it will _eventually_ be flushed to disk)
-> changes are logged to redo log
-> entry on undo logs(rollback segment)
-> Secondary index changes (if any) go into Change Buffer -- possibly triggering flush to make room
-> Execute `AFTER TRIGGERs`, if any
-> (if Galera involved) Write to gcache; coordinate with other nodes
-> if autocommit, redo log buffer flushed to redo logfile
-> deal with "group commit"?
-> binary logging happens(if enabled) -- or is this before COMMIT?
-> dirty pages write to double write buffer
-> If the Query Cache is enabled (and this is a write), invalidate all QC entries for the table(s) modified.
-> release eXclusive lock
-> success or failure returned to client
-> The block containing the row will be flushed to disk _later_
-> Index block updates will be done _later_ (cached read, apply Change Buffer, cached write, plus remove from CB)

我认为还有很多细节。我对确切的顺序含糊不清。

被触及的文件迟早包括

  • .frm 获取架构(缓存)(只读)
  • ibdata1.ibd -- 用于数据和任何已修改索引的“表空间”。 (读-修改-写)(参见innodb_file_per_table
  • 双写缓冲区(写)
  • iblog*(写)

这不包括在某些复杂的SELECTs 中创建的“临时”表; “元数据”锁定 ALTER TABLE 等内容。

【讨论】:

  • 是否可以将以下信息添加到您的答案中? gist.github.com/anonymous/7ae6fb196060e617336187dbd473dc2c
  • @iSR5 - 该链接专注于SELECT。这个问题专门针对一个普通的INSERT,它只会使部分QC失效,可能不需要任何优化。 (我添加了对 QC 的提及,但不知道它属于哪里。也移交给 Engine。)
  • 哦,那可能是不同的故事,即使循环将应用于所有查询,INSERT、UPDATE、TRUNCATE 和 DELETE 有更多的例外和条件。据我所知,这将刷新查询缓存,因为表已更改,但它会转到解析器并使用应用条件执行休息周期。某些条件可能会绕过某些其他阶段不会。
  • @iSR5 - 我遗漏了很多SELECT 阶段;您的链接包括其中一些。 TRUNCATE 不太像DELETE;它更像是一个 DDL 而不是 DML。 ALTERDROP 等属于另一个类别。 SHOWEXPLAIN 等也不同。完整的答案需要一本书,而不是简短的论坛答案。
  • 可能还会触发 BEFORE/AFTER INSERT 触发器。如果该语句等待 innodb_lock_wait_timeout 获取锁,或者作为死锁的受害者而被杀死,那么该语句的哪一部分可能在某个时候被杀死? (+10)
猜你喜欢
  • 2018-10-21
  • 2018-07-15
  • 1970-01-01
  • 2021-07-23
  • 2013-04-18
  • 2018-05-03
  • 1970-01-01
  • 1970-01-01
  • 2010-10-14
相关资源
最近更新 更多