MySQL優化(一):MySQL架構與SQL執行流程

  • 整理自網絡資料

我們操作數據庫有各種各樣的方式,比如 Linux 系統中的命令行,比如數據庫工具Navicat,比如程序: Java 語言的 JDBC API 或者 ORM 框架。

當工具或者程序連接到數據庫之後,實際上發生了什麼事情?它的內部是怎麼工作的?

以一條查詢語句爲例,我們來看下 MySQL 的工作流程是什麼樣的。

一、一條查詢SQL語句是如何執行的?

在這裏插入圖片描述

1. 通信協議

程序或者工具要操作數據庫,第一步要跟數據庫 建立連接 。這裏就涉及到了通信協議。
首先,MySQL 必須要運行一個服務,監聽默認的端口 3306。

1.1 通信協議

MySQL 支持多種通信協議,可以使用同步/異步的方式,支持長連接/短連接。

通信類型:同步或異步

一般來說我們的客戶端連接數據庫都是 同步 連接。

連接方式: 長連接或者短連接

MySQL 既支持短連接,也支持長連接。短連接就是操作完畢以後,馬上 close 掉。

長連接可以保持打開,減少服務端創建和釋放連接的消耗,後面的程序訪問的時候還可以使用這個連接。一般來說我們用的都是長連接 ,而且會把這個連接放到客戶端的連接池中。

保持長連接會消耗內存。長時間不活動的連接,MySQL 服務器會斷開。
在MySQL系統中有兩個參數進行控制:

show global variables like 'wait_timeout'; -- 非交互式超時時間, 如 JDBC 程序
show global variables like 'interactive_timeout'; -- 交互式超時時間, 如數據庫工具

在這裏插入圖片描述
在這裏插入圖片描述
兩個參數默認都是28800秒(8小時)。

怎麼查看 MySQL 當前有多少個連接

show global status like 'Thread%';

舉例,查詢結果爲:
在這裏插入圖片描述
Threads_cached:已緩存的連接數
Threads_connected:當前打開的連接數
Threads_created:已創建的連接數
Threads_running:當前未掛起的連接數

每產生一個連接或者一個會話,在服務端就會創建一個線程來處理。反之,如果要殺死會話,即 Kill 線程。

MySQL 服務允許的最大連接數是多少?

show variables like 'max_connections';

在這裏插入圖片描述

在 5.7 版本中默認是 151 個,最大可以設置成 100000。

show 命令的參數說明:
1、級別:會話 session 級別(默認);全局 global 級別
2、動態修改:set命令,重啓後失效,因爲每次重啓都要重新讀取配置文件;若要永久生效,需要修改配置文件 /etc/my.cnf(linux)my.ini(windows)

set global max_connections = 1000;

通信協議

MySQL 支持兩種通信協議。
第一種是 Unix Socket
比如我們在 Linux 服務器上,如果沒有指定-h 參數,它就用 socket 方式登錄。
在這裏插入圖片描述
它不用通過網絡協議,也可以連接到 MySQL 的服務器,它需要用到服務器上的一個物理文件(/var/lib/mysql/mysql.sock)。

如果指定-h 參數,就會用第二種方式, TCP/IP 協議
在這裏插入圖片描述

1.2 通信方式

在這裏插入圖片描述
單工:
在兩臺計算機通信的時候,數據的傳輸是單向的。如:遙控器。

半雙工:
在兩臺計算機之間,數據傳輸是雙向的,你可以給我發送,我也可以給你發送,
但是在這個通訊連接裏面,同一時間只能有一臺服務器在發送數據,也就是你要給我發
的話,也必須等我發給你完了之後才能給我發。如:對講機。

全雙工:
數據的傳輸是雙向的,並且可以同時傳輸。如:打電話。

MySQL 使用了 半雙工 的通信方式。要麼是客戶端向服務端發送數據,要麼是服務端向客戶端發送數據,這兩個動作不能同時發生。所以客戶端發送 SQL 語句給服務端的時候,在一次連接裏面數據是不能分成小塊發送的,不管你的 SQL 語句有多大,都是一次性發送。

比如我們用 MyBatis 動態 SQL 生成了一個批量插入的語句,插入 10 萬條數據,values後面跟了一長串的內容,或者 where 條件 in 裏面的值太多,會出現問題。

這個時候我們必須要調整 MySQL 服務器配置 max_allowed_packet 參數的值(默認是 4M),把它調大,否則就會報錯。

另一方面,對於服務端來說,也是一次性發送所有的數據,不能因爲你已經取到了想要的數據就中斷操作,這個時候會對網絡和內存產生大量消耗。

所以,我們一定要在程序裏面避免不帶 limit 的這種操作,比如一次把所有滿足條件的數據全部查出來。一定要先 count 一下。如果數據量大的話,可以分批查詢。

2. 查詢緩存

執行一條查詢語句,客戶端跟服務端建立連接之後,下一步就是查詢緩存。

MySQL 內部自帶了一個緩存模塊。執行相同的查詢之後我們發現緩存沒有生效,爲什麼?MySQL 的緩存默認是關閉的。

show variables like 'query_cache%';

在這裏插入圖片描述
默認關閉的意思就是不推薦使用,爲什麼 MySQL 不推薦使用它自帶的緩存呢?
主要是因爲 MySQL 自帶的緩存的應用場景有限,首先是它要求 SQL 語句必須一模一樣,中間多一個空格,字母大小寫不同都被認爲是不同的的 SQL。
其次是表裏面任何一條數據發生變化的時候,這張表所有緩存都會失效,所以對
於有大量數據更新的應用,也不適合。
所以緩存還是交給 ORM 框架(比如 MyBatis 默認開啓了一級緩存),或者獨立的緩存服務,比如 Redis 來處理更合適。
在 MySQL 8.0 中,查詢緩存已經被移除了。

3. 語法解析和預處理(Parser & Preprocessor)

爲什麼一條 SQL 語句能夠被識別呢?假如隨便執行一個字符串 ,服務器
報了一個 1064 的錯:

[Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'penyuyan' at line 1

這個就是 MySQL 的 Parser 解析器和 Preprocessor 預處理模塊。
這一步主要做的事情是對語句,基於 SQL 語法進行詞法和語法分析和語義的解析。

3.1 詞法解析

詞法分析就是把一個完整的 SQL 語句打碎成一個個的單詞。
比如一個簡單的 SQL 語句:


select name from user where id = 1;

它會被打碎成 8 個符號,每個符號是什麼類型,從哪裏開始到哪裏結束,就是詞法解析要做的事情。

3.2 語法解析

第二步就是語法分析,語法分析會對 SQL 做一些語法檢查,比如單引號有沒有閉合,
然後根據 MySQL 定義的語法規則,根據 SQL 語句生成一個數據結構。這個數據結構我
們把它叫做 解析樹(select_lex)
在這裏插入圖片描述

3.3 預處理器

如果寫了一個詞法和語法都正確的 SQL,但是表名或者字段不存在,會在哪裏報錯?是在數據庫的執行層還是解析器?比如:

select * from zhuzhu;

假設zhuzhu表不存在。
答案是在解析的時候報錯,解析 SQL 的環節裏面有預處理器,它會檢查生成的解析樹,解決解析器無法解析的語義。
比如,它會檢查表和列名是否存在,檢查名字和別名,保證沒有歧義。預處理之後得到一個新的解析樹。

4. 查詢優化( Query Optimizer) 與查詢執行計劃

4.1 優化器概念

一條SQL語句是不是隻有一種執行方式?或者說數據庫最終執行的SQL是不是就是我們發送的 SQL?

這個答案是否定的。一條 SQL 語句是可以有很多種執行方式的,最終返回相同的結果,他們是等價的。但是如果有這麼多種執行方式,這些執行方式怎麼得到的?最終選擇哪一種去執行?根據什麼判斷標準去選擇?

這個就是 MySQL 的 查詢優化器(Optimizer)模塊。

查詢優化器的目的就是根據解析樹生成不同的 執行計劃(Execution Plan),然後選擇一種最優的執行計劃,MySQL 裏面使用的是基於 開銷(cost)的優化器,哪種執行計劃開銷最小,就用哪種。

可以使用這個命令查看查詢的開銷:

show status like 'Last_query_cost';

4.2 優化器作用

MySQL 的優化器能處理哪些優化類型呢?

舉兩個簡單的例子:
1、當我們對多張表進行關聯查詢的時候,以哪個表的數據作爲基準表。
2、有多個索引可以使用的時候,選擇哪個索引。

實際上,對於每一種數據庫來說,優化器的模塊都是必不可少的,他們通過複雜的算法實現儘可能優化查詢效率的目標。但是優化器也不是萬能的,並不是再垃圾的 SQL語句都能自動優化,也不是每次都能選擇到最優的執行計劃,大家在編寫 SQL 語句的時候還是要注意。

4.3 優化器結果

優化器最終會把解析樹變成一個執行計劃(execution_plans),執行計劃是一個數據結構。當然,這個執行計劃不一定是最優的執行計劃,因爲 MySQL 也有可能覆蓋不到所有的執行計劃。

我們怎麼查看 MySQL 的執行計劃呢?比如多張表關聯查詢,先查詢哪張表?在執行查詢的時候可能用到哪些索引,實際上用到了什麼索引?

MySQL 提供了一個執行計劃的工具。我們在 SQL 語句前面加上 EXPLAIN ,就可以
看到執行計劃的信息。

EXPLAIN select name from user where id=1;

5. 存儲引擎

1、從邏輯的角度來說,我們的數據是放在哪裏的,或者說放在一個什麼結構裏面?
2、執行計劃在哪裏執行?是誰去執行?

5.1 存儲引擎基本介紹

在關係型數據庫裏面,數據是放在表 Table 裏面的。我們可以把這個表理解成 Excel電子表格的形式。所以我們的表在存儲數據的同時,還要組織數據的存儲結構,這個存儲結構就是由我們的 存儲引擎 決定的,所以我們也可以把存儲引擎叫做表類型

在 MySQL 裏面,支持多種存儲引擎,他們是可以替換的,所以叫做插件式的存儲引擎。爲什麼要支持這麼多存儲引擎呢?一種還不夠用嗎?這個問題先留着。

5.2 查看存儲引擎

數據庫裏面已經存在的表,怎麼查看它們的存儲引擎呢?

show table status from `gupao`;

在這裏插入圖片描述
或者通過 DDL 建表語句來查看。

在 MySQL 裏面,每一張表都可以指定它的存儲引擎,而不是一個數據庫只能使用一個存儲引擎。存儲引擎的使用是以表爲單位的。而且,創建表之後還可以修改存儲引擎。

我們說一張表使用的存儲引擎決定我們存儲數據的結構,那在服務器上它們是怎麼存儲的呢?我們先要找到數據庫存放數據的路徑:


show variables like 'datadir';

在這裏插入圖片描述
默認情況下,每個數據庫有一個自己文件夾,以 test2 數據庫爲例。
任何一個存儲引擎都有一個 frm 文件,這個是表結構的定義文件。
在這裏插入圖片描述
不同的存儲引擎存放數據的方式不一樣,產生的文件也不一樣,innodb 是 1 個,memory 沒有,myisam 是兩個。

這些存儲引擎的差別在哪呢?

5.3 存儲引擎比較

  • 數據庫支持的存儲引擎

我們可以用這個命令查看數據庫對存儲引擎的支持情況:

show engines ;

在這裏插入圖片描述
其中有存儲引擎的描述和對事務、XA 協議和 Savepoints 的支持。

XA 協議用來實現分佈式事務(分爲本地資源管理器,事務管理器)。
Savepoints 用來實現子事務(嵌套事務)。創建了一個 Savepoints 之後,事務就可以回滾到這個點,不會影響到創建 Savepoints 之前的操作。

這些數據庫支持的存儲引擎,分別有什麼特性呢?
可查閱官方文檔

MyISAM

( 3 個文件)
MySQL 自帶的存儲引擎,由 ISAM 升級而來。

應用範圍比較小。表級鎖定限制了讀/寫的性能,因此在 Web 和數據倉庫配置中,它通常用於只讀或以讀爲主的工作。

特點:
支持表級別的鎖(插入和更新會鎖表)。不支持事務
擁有較高的插入(insert)和查詢(select)速度。
存儲了表的行數(count 速度更快)。
(怎麼快速向數據庫插入 100 萬條數據?我們有一種先用 MyISAM 插入數據,然後修改存儲引擎爲 InnoDB 的操作。)
適合:只讀之類的數據分析的項目。

InnoDB

( 2 個文件)
mysql (5.1以後) 的默認存儲引擎。InnoDB 是一個事務安全(與 ACID 兼容)的 MySQL存儲引擎,它具有提交、回滾和崩潰恢復功能來保護用戶數據。

InnoDB 行級鎖(不升級爲更粗粒度的鎖)和 Oracle 風格的一致非鎖讀提高了多用戶併發性和性能。

InnoDB 將用戶數據存儲在聚集索引中,以減少基於主鍵的常見查詢的 I/O。爲了保持數據完整性,InnoDB 還支持外鍵引用完整性約束。

特點:
支持事務,支持外鍵,因此數據的完整性、一致性更高。
支持行級別的鎖和表級別的鎖。
支持讀寫併發,寫不阻塞讀(MVCC)。
特殊的索引存放方式,可以減少 IO,提升查詢效率。
適合:經常更新的表,存在併發讀寫或者有事務處理的業務系統。

Memory

( 1 個文件)
將所有數據存儲在 RAM 中,以便在需要快速查找非關鍵數據的環境中快速訪問。這個引擎以前被稱爲堆引擎。其使用案例正在減少;InnoDB 及其緩衝池內存區域提供了一種通用、持久的方法來將大部分或所有數據保存在內存中,而 ndbcluster 爲大型分佈式數據集提供了快速的鍵值查找。

特點:
把數據放在內存裏面,讀寫的速度很快,但是數據庫重啓或者崩潰,數據會全部消失。只適合做臨時表。
將表中的數據存儲到內存中。默認使用哈希索引。

CSV

(3個文件)
它的表實際上是帶有逗號分隔值的文本文件。csv表允許以csv格式導入或轉儲數據,以便與讀寫相同格式的腳本和應用程序交換數據。因爲 csv 表沒有索引,所以通常在正常操作期間將數據保存在 innodb 表中,並且只在導入或導出階段使用 csv 表。

特點:不允許空行,不支持索引。格式通用,可以直接編輯,適合在不同數據庫之間導入導出。

Archive

( 2 個文件)
從archive單詞的解釋我們大概可以明白這個存儲引擎的用途,這個存儲引擎基本上用於數據歸檔;
它的壓縮比非常的高,存儲空間大概是innodb的10-15分之一所以它用來存儲歷史數據非常的適合,由於它不支持索引同時也不能緩存索引和數據,所以它不適合作爲併發訪問表的存儲引擎。
Archivec存儲引擎使用行鎖來實現高併發插入操作,但是它不支持事務,其設計目標只是提供高速的插入和壓縮功能。

5.4 如何選擇存儲引擎

如果對數據一致性要求比較高,需要 事務 支持,可以選擇 InnoDB。
如果數據查詢多更新少,對 查詢 性能要求比較高,可以選擇 MyISAM。
如果需要一個用於查詢的臨時表,可以選擇 Memory。

如果所有的存儲引擎都不能滿足你的需求,並且技術能力足夠,可以根據官網內部手冊用 C 語言開發一個存儲引擎:
-> 手冊

6. 執行引擎

誰使用執行計劃去操作存儲引擎呢?這就是 執行引擎 (執行器 Query Execution Engine),它利用存儲引擎提供的相應的 API 來完成操作。

爲什麼我們修改了表的存儲引擎,操作方式不需要做任何改變?因爲不同功能的存儲引擎實現的 API 是相同的。

執行最後把數據返回給客戶端,即使沒有結果也要返回。

二、MySQL 體系結構總結

清楚了SQL的執行流程後,現在總結一下涉及到的模塊。

1. 模塊詳解

在這裏插入圖片描述
1、 Connector:用來支持各種語言和 SQL 的交互,比如 PHP,Python,Java 的JDBC;
2、 Management Serveices & Utilities:系統管理和控制工具,包括備份恢復、MySQL 複製、集羣等等;
3、 Connection Pool:連接池,管理需要緩衝的資源,包括用戶密碼權限線程等等;
4、 SQL Interface:用來接收用戶的 SQL 命令,返回用戶需要的查詢結果
5、 Parser:用來解析 SQL 語句;
6、 Optimizer:查詢優化器;
7、 Cache and Buffer:查詢緩存,除了行記錄的緩存之外,還有表緩存,Key 緩存,權限緩存等等;
8、 Pluggable Storage Engines:插件式存儲引擎,它提供 API 給服務層使用,跟具體的文件打交道。

2. 架構分層

總體上,我們可以把 MySQL 分成三層,跟客戶端對接的 連接層 ,真正執行操作的 服務層 ,和跟硬件打交道的 存儲引擎層 (參考 MyBatis:接口、核心、基礎)。
在這裏插入圖片描述

2.1 連接層

我們的客戶端要連接到 MySQL 服務器 3306 端口,必須要跟服務端建立連接,那麼管理所有的連接,驗證客戶端的身份和權限,這些功能就在連接層完成。

2.2 服務層

連接層會把 SQL 語句交給服務層,這裏面又包含一系列的流程:
比如查詢緩存的判斷、根據 SQL 調用相應的接口,對我們的 SQL 語句進行詞法和語法的解析(比如關鍵字怎麼識別,別名怎麼識別,語法有沒有錯誤等等)。
然後就是優化器,MySQL 底層會根據一定的規則對我們的 SQL 語句進行優化,最後再交給執行器去執行。

2.3 存儲引擎層

存儲引擎就是我們的數據真正存放的地方,在 MySQL 裏面支持不同的存儲引擎。再往下就是內存或者磁盤。

三、一條更新SQL語句是如何執行的?

更新流程和查詢流程有什麼不同呢?
基本流程也是一致的,也就是說,它也要經過解析器、優化器的處理,最後交給執行器。區別就在於查到符合條件的數據之後的操作。

3.1 緩衝池(Buffer Pool)

首先,InnnoDB 的數據都是放在磁盤上的,存儲引擎要操作數據,必須先把磁盤裏面的數據加載到內存裏面。

這裏就有個問題,是不是我們需要的數據多大,我們就一次從磁盤加載多少數據到內存呢?

磁盤 I/O 的讀寫相對於內存的操作來說是很慢的。如果我們需要的數據分散在磁盤的不同的地方,那就意味着會產生很多次的 I/O 操作。這樣一來,我們乾脆每次多讀取一點,而不是用多少讀多少。

所以,無論是操作系統的文件管理系統也好,還是存儲引擎也好,都有一個預讀取的概念。也就是說,當磁盤上的一塊數據被讀取的時候,很有可能它附近的位置也會馬上被讀取到,這個就叫做局部性原理。

存儲引擎從磁盤讀取數據到內存的最小的單位,叫做。操作系統也有頁的概念。操作系統的頁大小一般是 4K,而在 InnoDB 裏面,這個最小的單位默認是 16KB 大小,頁,是一個邏輯單位。

我們要操作的數據就在這樣的頁裏面,數據所在的頁叫數據頁。

我們對於數據頁的操作,不是每次都直接操作磁盤,因爲磁盤的速度太慢了。InnoDB使用了一種緩衝池的技術,也就是把磁盤讀到的頁放到一塊內存區域裏面。下一次讀取相同的頁,先判斷是不是在這個內存區域裏面,如果是,就直接讀取,不用再次訪問磁盤

這個內存區域就叫 Buffer Pool

在這裏插入圖片描述

3.2 InnoDB 內存結構和磁盤結構

官方文檔
在這裏插入圖片描述

3.2.1 內存結構

(1)Buffer Pool

官方文檔
Buffer Pool 緩存的是 page 頁面信息。查看服務器狀態,裏面有很多跟 Buffer Pool相關的信息:

SHOW STATUS LIKE '%innodb_buffer_pool%';

Buffer Pool 默認大小是 128M(134217728 字節),可以調整。

查看參數(系統變量):

SHOW VARIABLES like '%innodb_buffer_pool%';

(2)redo log

思考一個問題:如果 Buffer Pool 裏面的髒頁還沒有刷入磁盤時,數據庫宕機或者重啓,這些數據丟失。

爲了避免這個問題,InnoDB 把所有對頁面的修改操作專門寫入一個日誌文件,並且在數據庫啓動時從這個文件進行恢復操作(實現 crash-safe)——用它來實現事務的持久性

在這裏插入圖片描述
這個文件就是磁盤的 redo log(重做日誌),對應於/var/lib/mysql/目錄下的ib_logfile0 和 ib_logfile1,每個 48M。
這種日誌和磁盤配合的整個過程 ,其實就是MySQL裏的WAL技術(Write-Ahead Logging),它的關鍵點就是先寫日誌,再寫磁盤。

show variables like 'innodb_log%';

在這裏插入圖片描述
那麼問題來了:
同樣是寫磁盤,爲什麼不直接寫到 db file 裏面去?爲什麼先寫日誌再寫磁盤?

我們先來了解一下隨機 I/O 和順序 I/O 的概念。

如果我們所需要的數據是隨機分散在磁盤上不同頁的不同扇區中,那麼找到相應的數據需要等到磁臂旋轉到指定的頁,然後盤片尋找到對應的扇區,才能找到我們所需要的一塊數據,依次進行此過程直到找完所有數據,這個就是隨機 IO,讀取數據速度較慢。

假設我們已經找到了第一塊數據,並且其他所需的數據就在這一塊數據後邊,那麼就不需要重新尋址,可以依次拿到我們所需的數據,這個就叫順序 IO。

刷盤是隨機 I/O,而記錄日誌是順序 I/O(連續寫的),順序 I/O 效率更高。因此先把修改寫入日誌文件,在保證了內存數據的安全性的情況下,可以延遲刷盤時機,進而提升系統吞吐。

這個 redo log 有什麼特點?

  1. redo log 是 InnoDB 存儲引擎實現的,並不是所有存儲引擎都有。支持崩潰恢復是 InnoDB 的一個特性。

  2. 不是記錄數據頁更新之後的狀態,而是記錄這個頁做了什麼改動,屬於物理日誌

  3. redo log 的大小是固定的,前面的內容會被覆蓋,一旦寫滿,就會觸發 redo log到磁盤的同步,以便騰出空間記錄後面的修改。

除了 redo log 之外,還有一個跟修改有關的日誌,叫做 undo log。redo log 和 undo log 與事務密切相關,統稱爲事務日誌

(3)undo log

官方文檔

undo log(撤銷日誌或回滾日誌)記錄了事務發生之前的數據狀態(不包括 select)。

如果修改數據時出現異常,可以用 undo log 來實現回滾操作(保持原子性)。

在執行 undo 的時候,僅僅是將數據從邏輯上恢復至事務之前的狀態,而不是從物理頁面上操作實現的,屬於邏輯格式的日誌。

undo Log 的數據默認在系統表空間 ibdata1 文件中,因爲共享表空間不會自動收縮,也可以單獨創建一個 undo 表空間。

查看:

show global variables like '%undo%';

(4)小結

有了這些日誌之後,我們來總結一下一個更新操作的流程,這是一個簡化的過程。

name 原值是zhuzhu。執行如下語句:

update user set name = 'xiaoming' where id=1;

1、事務開始,從內存或磁盤取到這條數據,返回給 Server 的執行器;
2、執行器修改這一行數據的值爲 xiaoming;
3、記錄 name=zhuzhu 到 undo log;
4、記錄 name=xiaoming 到 redo log;
5、調用存儲引擎接口,在內存(Buffer Pool)中修改 name=xiaoming;
6、事務提交。

內存和磁盤之間,工作着很多後臺線程。

3.2.2 後臺線程

內存和磁盤之間,工作着很多後臺線程。

後臺線程的主要作用是,負責刷新內存池中的數據和把修改的數據頁刷新到磁盤。

後臺線程分爲:master thread,IO thread,purge thread,page cleaner thread。

3.3 Binlog

官方文檔
除了 InnoDB 架構中的日誌文件,MySQL 的 Server 層也有一個日誌文件,叫做binlog,它可以被所有的存儲引擎使用。

binlog 以事件的形式記錄了所有的 DDL 和 DML 語句(因爲它記錄的是操作而不是數據值,屬於邏輯日誌),可以用來做主從複製和數據恢復。

跟 redo log 不一樣,它的文件內容是可以追加的,沒有固定大小限制。

在開啓了 binlog 功能的情況下,我們可以把 binlog 導出成 SQL 語句,把所有的操作重放一遍,來實現數據的恢復

binlog 的另一個功能就是用來實現主從複製,它的原理就是從服務器讀取主服務器的 binlog,然後執行一遍。

3.4 完整流程

有了這兩個日誌之後,我們來看一條更新語句是怎麼執行的(redo 不是一次寫入了):

update user set name = 'xiaoming' where id=1;

在這裏插入圖片描述

  1. 先查詢到這條數據,如果有緩存,也會用到緩存。

  2. 把 name 改成xiaoming,然後調用存儲引擎的 API 接口,寫入這一行數據到內存,同時記錄 redo log。這時 redo log 進入 prepare 狀態,然後告訴執行器,執行完成了,可以隨時提交。

  3. 執行器收到通知後記錄 binlog,然後調用存儲引擎接口,設置 redo log爲 commit狀態。

  4. 更新完成。

總結一下這張圖片的重點:

  1. 先記錄到內存(buffer pool),再寫日誌文件。
  2. 記錄 redo log 分爲兩個階段(prepare 和 commit)
  3. 存儲引擎和 server 分別記錄不同的日誌。
  4. 先記錄 redo,再記錄 binlog
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章