什麼是數據庫的 “緩存池” ?(萬字乾貨)

原創屬於 坨坨,轉發 程序員小灰

 

1、Buffer Pool 概述

Buffer Pool 是什麼?從字面上看是緩存池的意思,沒錯,它其實也就是緩存池的意思。它是 MySQL 當中至關重要的一個組件,可以這麼說,MySQL的所有的增刪改的操作都是在 Buffer Pool 中執行的。

但是數據不是在磁盤中的嗎?怎麼會和緩存池又有什麼關係呢?那是因爲如果 MySQL的操作都在磁盤中進行,那很顯然效率是很低的,效率爲什麼低?因爲數據庫要從磁盤中拿數據啊,那肯定就需要IO啊,並且數據庫並不知道它將要查找的數據是磁盤的哪個位置,所以這就需要進行隨機IO,那這個性能簡直就別玩了。所以 MySQL對數據的操作都是在內存中進行的,也就是在 Buffer Pool 這個內存組件中。

實際上他就好比是 Redis,因爲 Redis 是一個內存是數據庫,他的操作就都是在內存中進行的,並且會有一定的策略將其持久化到磁盤中。那 Buffer Pool 的內存結構具體是什麼樣子的,那麼多的增刪改操作難道數據要一直在內存中嗎?既然說類似 redis 緩存,那是不是也像 redis 一樣也有一定的淘汰策略呢?

本篇文章,會詳細的介紹 Buffer Pool 的內存結構,讓大家徹底明白這裏面的每一步執行流程。我們先看一下 MySQL從加載磁盤文件到完成提交一個事務的整個流程。我們先來看一個總體的流程圖,從數據在磁盤中被加載到緩存池中,然後經過一些列的操作最終又被刷入到磁盤的一個過程,都經歷了哪些事情,這個圖不明白沒有關係,因爲本文重點是 Buffer Pool 這個整體的流程就是讓大家稍微有個印象。

 

 

 

2、Buffer Pool 有多大

Buffer Pool 是 InnoDB 中的一塊內存區域,他一定是有自己的大小的,且大小默認是 128M,不過這個容量似乎有點小了,大家的自己的生產環境可以根據實際的內存大小進行調整,參數爲:innodb_buffer_pool_size=2147483648 單位是字節,

# 查看和調整innodb_buffer_pool_size
1. 查看@@innodb_buffer_pool_size大小,單位字節
SELECT @@innodb_buffer_pool_size/1024/1024/1024; #字節轉爲G

2. 在線調整InnoDB緩衝池大小,如果不設置,默認爲128M
set global innodb_buffer_pool_size = 4227858432; ##單位字節

  他在 InnoDB 中的整體結構大概是這樣子的

 

 

 

3、數據頁

剛剛介紹到 MySQL在執行增刪改的時候數據是會被加載到 Buffer Pool 中的,既然這樣數據是怎麼被加載進來的,是一條一條還是說是以其他的形式呢。我們操作的數據都是以表 + 行的方式,而表 + 行僅僅是邏輯上的概念,MySQL並不會像我們一樣去操作行數據,而是抽象出來一個一個的數據頁概念,每個數據頁的大小默認是 16KB,這些參數都是可以調整的。但是建議使用默認的就好,畢竟 MySQL能做到極致的都已經做了。每個數據頁存放着多條的數據,MySQL在執行增刪改首先會定位到這條數據所在數據頁,然後會將數據所在的數據頁加載到 Buffer Pool 中。

4、緩存頁

當數據頁被加載到緩衝池中後,Buffer Pool 中也有叫緩存頁的概念與其一一對應,大小同樣是 16KB,但是 MySQL還爲每個緩存也開闢額外的一些空間,用來描述對應的緩存頁的一些信息,例如:數據頁所屬的表空間,數據頁號,這些描述數據塊的大小大概是緩存頁的15%左右(約800B)。

 

# 緩存頁是什麼時候被創建的?
當 MSql 啓動的時候,就會初始化 Buffer Pool,這個時候 MySQL 會根據系統中設置的 innodb_buffer_pool_size 大小去內存中申請一塊連續的內存空間,實際上在這個內存區域比配置的值稍微大一些,因爲【描述數據】也是佔用一定的內存空間的,當在內存區域申請完畢之後, MySql 會根據默認的緩存頁的大小(16KB)和對應`緩存頁*15%`大小(800B左右)的數據描述的大小,將內存區域劃分爲一個個的緩存頁和對應的描述數據

 

5、Free鏈表

上面是說了每個數據頁會被加載到一個緩存頁中,但是加載的時候 MySQL是如何知道那個緩存頁有數據,那個緩存頁沒有數據呢?換句話說, MySQL是怎麼區分哪些緩存頁是空閒的狀態,是可以用來存放數據頁的。

爲了解決這個問題, MySQL 爲 Buffer Pool 設計了一個雙向鏈表— free鏈表,這個 free 鏈表的作用就是用來保存空閒緩存頁的描述塊(這句話這麼說其實不嚴謹,換句話:每個空閒緩存頁的描述數據組成一個雙向鏈表,這個鏈表就是free鏈表)。之所以說free鏈表的作用就是用來保存空閒緩存頁的描述數據是爲了先讓大家明白 free 鏈表的作用,另外 free 鏈表還會有一個基礎節點,他會引用該鏈表的頭結點和尾結點,還會記錄節點的個數(也就是可用的空閒的緩存頁的個數)。

這個時候,他可以用下面的圖片來描述:

 

 

 

當加載數據頁到緩存池中的時候, MySQL會從 free 鏈表中獲取一個描述數據的信息,根據描述節點的信息拿到其對應的緩存頁,然後將數據頁信息放到該緩存頁中,同時將鏈表中的該描述數據的節點移除。這就是數據頁被讀取 Buffer Pool 中的緩存頁的過程。

 MySQL是怎麼知道哪些數據頁已經被緩存了,哪些沒有被緩存呢。實際上數據庫中還有後一個哈希表結構,他的作用是用來存儲表空間號 + 數據頁號作爲數據頁的key,緩存頁對應的地址作爲其value,這樣數據在加載的時候就會通過哈希表中的key來確定數據頁是否被緩存了。

 

 

 

6、Flush鏈表

MySql 在執行增刪改的時候會一直將數據以數據頁的形式加載到 Buffer Pool 的緩存頁中,增刪改的操作都是在內存中執行的,然後會有一個後臺的線程數將髒數據刷新到磁盤中,但是後臺的線程肯定是需要知道應該刷新哪些啊。

針對這個問題,MySQL設計出了 Flush 鏈表,他的作用就是記錄被修改過的髒數據所在的緩存頁對應的描述數據。如果內存中的數據和數據庫和數據庫中的數據不一樣,那這些數據我們就稱之爲髒數據,髒數據之所以叫髒數據,本質上就是被緩存到緩存池中的數據被修改了,但是還沒有刷新到磁盤中。

同樣的這些已經被修改了的數據所在的緩存頁的描述數據會被維護到 Flush 中(其實結構和 free 鏈表是一樣的),所以 Flush 中維護的是一些髒數據數據描述(準確地說是髒數據的所在的緩存頁的數據描述)

另外,當某個髒緩存頁被刷新到磁盤後,其空間就騰出來了,然後又會跑到 Free 鏈表中了。

 

 

7、LRU鏈表

如果系統一直在進行數據庫的增刪改操作,數據庫內部的基本流程就是:

 

 

 

我們還拿 redis 做類比,以便更好的幫助大家明白其原理。Flush 的作用其實類似 redis 的 key 設置的過期時間,所以一般情況下,redis 內存不會不夠使用,但是總有特殊的情況,問題往往就是在這種極端和邊邊角角的情況下產生的。

如果 redis 的內存不夠使用了,是不是自己還有一定的淘汰策略?最基本的準則就是淘汰掉不經常使用到的key。Buffer Pool 也類似,它也會有內存不夠使用的情況,它是通過 LRU 鏈表來維護的。LRU 即 Least Recently Uesd(最近最少使用)。

MySql 會把最近使用最少的緩存頁數據刷入到磁盤去,那 MySql 如何判斷出 LRU 數據的呢?爲此 MySql 專門設計了 LUR 鏈表,還引入了另一個概念:緩存命中率

# 緩存命中率
可以理解爲緩存被使用到的頻率,舉個例子來說:現在有兩個緩存頁,在100次請求中A緩存頁被命中了20次,B緩存頁被命中了2次,很顯然A緩存頁的命中率更高,這也就意味着A在未來還會被使用到的可能性比較大,而B就會被 MySQL 認爲基本不會被使用到;

說到這裏,那LRU究竟是怎麼工作的。假設 MySQL在將數據加載到緩存池的時候,他會將被加載進來的緩存頁按照被加載進來的順序插入到LRU鏈表的頭部(就是鏈表的頭插法),假設 MySQL現在先後分別加載A、B、C數據頁到緩存頁A、B、C中,然後 LRU 的鏈表大致是這樣子的。

 

 

 現在又來了一個請求,假設查詢到的數據是已經被緩存在緩存頁B中,這時候 MySQL就會將B緩存頁對應的描述信息插入到LRU鏈表的頭部,如下圖:

 

 

 然後又來了一個請求,數據是已經被緩存在了緩存頁C中,然後LRU會變成這樣子:

 

 

 說到底,每次查詢數據的時候如果數據已經在緩存頁中,那麼就會將該緩存頁對應的描述信息放到LRU鏈表的頭部,如果不在緩存頁中,就去磁盤中查找,如果查找到了,就將其加載到緩存中,並將該數據對應的緩存頁的描述信息插入到LRU鏈表的頭部。也就是說最近使用的緩存頁都會排在前面,而排在後面的說明是不經常被使用到的。

最後,如果 Buffer Pool 不夠使用了,那麼 MySQL就會將 LRU 鏈表中的尾節點刷入到磁盤中,用來給 Buffer Pool 騰出內存空間。來個整體的流程圖給大家看下

 

 

 

8、LRU鏈表帶來的麻煩

這裏的麻煩指的是就是 MySQL本身的預讀機制帶來的問題

# 預讀機制
MySQL 在從磁盤加載數據的的時候,會將數據頁的相鄰的其他的數據頁也加載到緩存中。

# MySQL 爲什麼要這麼做
因爲根據經驗和習慣,一般查詢數據的時候往往還會查詢該數據相鄰前後的一些數據,有人可能會反問:一個數據頁上面不是就會存在該條數據相鄰的數據嗎?這可不一定,某條數據可能很大,也可能這條數據是在數據頁在頭部,也可能是在數據頁的尾部,所以 MySQL 爲了提高效率,會將某個數據頁的相鄰的數據頁也加載到緩存池中。

 

 

 

 

上圖能夠看到B的相鄰也被加載到了C描述數據的前面,而實際上C的命中率比B的相鄰頁高多了,這就是LRU本身帶來的問題。

# 哪些情況會觸發預讀機制
1. 有一個參數是 innodb_read_ahead_threshold, 他的默認值是56,意思就是如果順序的訪問了一個區裏的多個數據頁,訪問的數據頁的數量超過了這個閾值,此時就會觸發預讀機制,把下一個相鄰區中的所有數據頁都加載到緩存裏去(這種就是:線性預讀)

還有一種情況是 SELECT * FROM students 這種直接全表掃描的,會直接加載表中的所有的數據到緩存中,這些數據基本是加載的時候查詢一次,後面就基本使用不到了,但是加載這麼多數據到鏈表的頭部就將其他的經常命中的緩存頁直接全擠到後面去了。

以上種種跡象表明,預讀機制帶來的問題還是蠻大的,既然這麼大,那 MySQL爲什麼還要進入預讀機制呢,說到底還是爲了提高效率,**一種新的技術的引進,往往帶來新的挑戰**,下面我們就一起來看下 MySQL是如何解決預加載所帶來的麻煩的。

9、基於冷熱數據分離的LRU鏈表

所謂的冷熱分離,就是將 LRU 鏈表分成兩部分,一部分是經常被使用到的熱數據,另一部分是被加載進來但是很少使用的冷數據。通過參數innodb_old_blocks_pct 參數控制的,默認爲37,也就是 37% 。用圖表示大致如下:

 

 

 

數據在從磁盤被加載到緩存池的時候,首先是會被放在冷數據區的頭部,然後在一定時間之後,如果再次訪問了這個數據,那麼這個數據所在的緩存頁對應描述數據就會被放轉移到熱數據區鏈表的頭部。

那爲什麼說是在一定的時間之後呢,假設某條數據剛被加載到緩存池中,然後緊接着又被訪問了一次,這個時候假設就將其轉移到熱數據區鏈表的頭部,但是以後就再也不會被使用了,這樣子是不是就還是會存在之前的問題呢?

所以 MySQL通過innodb_old_blocks_time來設置數據被加載到緩存池後的多少時間之後再次被訪問,纔會將該數據轉移到熱數據區鏈表的頭部,該參數默認是1000單位爲:毫秒,也就是1秒之後,如果該數據又被訪問了,那麼這個時候纔會將該數據從 LRU 鏈表的冷數據區轉移到熱數據區。

現在再回頭看下上面的問題

# 通過預加載(加載相鄰數據頁)進來的數據
1. 這個時候就很好理解了,反正數據會被放在LRU鏈表的冷數據區的(注意:這裏說的放在鏈表中的數據都是指的是<緩存頁中的數據所對應的描述數據>),當在指定時候之後,如果某些緩存頁被訪問了那麼就將該緩存頁的描述數據放到熱數據區鏈表的頭部

# 全表掃描加載進來的數據頁
1. 和上面一樣,數據都是先在冷數據區,然後在一定時間之後,再次被訪問到的數據頁纔會轉移到熱數據區的鏈表的頭結點,所以這也就很好的解決了全表掃描所帶來的問題

再來思考下 Buffer Pool 內存不夠的問題

# Buffer Pool 內存空間不夠使用了怎麼辦?也就是說沒有足夠使用的空閒的緩存頁了。
1. 這個問題在這個時候就顯得非常簡單了,直接將鏈表冷數據區的尾節點的描述數據多對應的緩存頁刷到磁盤即可。

但是這樣子還不是足夠完美,爲什麼這麼說,剛剛我們一直在討論的是冷數據區的數據被訪問,然後在一定規則之下會被加載到熱數據鏈表的頭部,但是現在某個請求需要訪問的數據就在熱數據區,那是不是直接把該數據所在的緩存頁對應的描述數據轉移到熱數據區鏈表頭部呢?

很顯然不是這樣子的,因爲熱數據區的數據本身就是會被頻繁訪問的,這樣子如果每次訪問都去移動鏈表,勢必造成性能的下降(影響再小極端情況下也可能會不可控),所以MySQL針對熱數據區的數據的轉移也有相關的規則。

該規則就是:如果被訪問的數據所在的緩存頁在熱數據區的前25%,那麼該緩存頁對應的描述數據是不會被轉移到熱數據鏈表的頭部的,只有當被訪問的緩存頁對應的描述數據在熱數據區鏈表的後75%,該緩存頁的描述數據纔會被轉移到熱數據鏈表的頭部

舉個例子來說,假設熱數據區有100個緩存頁(這裏的緩存頁還是指的是緩存頁對應的描述數據,再強調下,鏈表中存放的是緩存頁的描述數據,爲了方便有時候會直接說緩存頁。希望朋友們注意),當被訪問的緩存頁在前25個的時候,熱數據區的鏈表是不會有變化的,當被訪問的緩存頁在26~100(也就是數據在熱數據區鏈表的後75%裏面)的時候,這個時候被訪問的緩存頁纔會被轉移到鏈表的頭部。

到此爲止, MySQL對於LUR 鏈表的優化就堪稱完美了。是不是看到這裏瞬間感覺很多東西都明朗了,好了,對於 LRU 鏈表我們就討論到這裏了。

 

10、Buffer Pool 中的鏈表小結

# free鏈表
用來存放空閒的緩存頁的描述數據,如果某個緩存頁被使用了,那麼該緩存頁對應的描述數據就會被從free鏈表中移除

# flush鏈表
被修改的髒數據都記錄在 Flush 中,同時會有一個後臺線程會不定時的將 Flush 中記錄的描述數據對應的緩存頁刷新到磁盤中,如果某個緩存頁被刷新到磁盤中了,那麼該緩存頁對應的描述數據會從 Flush 中移除,同時也會從LRU鏈表中移除(因爲該數據已經不在 Buffer Pool 中了,已經被刷入到磁盤,所以就也沒必要記錄在 LRU 鏈表中了),同時還會將該緩存頁的描述數據添加到free鏈表中,因爲該緩存頁變得空閒了。

# LRU鏈表
數據頁被加載到 Buffer Pool 中的對應的緩存頁後,同時會將緩存頁對應的描述數據放到 LRU 鏈表的冷數據的頭部,當在一定時間過後,冷數據區的數據被再次訪問了,就會將其轉移到熱數據區鏈表的頭部,如果被訪問的數據就在熱數據區,那麼如果是在前25%就不會移動,如果在後75%仍然會將其轉移到熱數據區鏈表的頭部

後臺線程將冷數據區的尾節點的描述數據對應的緩存頁刷入磁盤文件中

 

 

11、Buffer Pool 的併發性能

我們平時的系統絕對不可能每次只有一個請求來訪問的,說白了就是如果多個請求同時來執行增刪改,那他們會並行的去操作 Buffer Pool 中的各種鏈表嗎?如果是並行的會不會有什麼問題。

實際上 MySQL在處理這個問題的時候考慮的非常簡單,就是: Buffer Pool 一次只能允許一個線程來操作,一次只有一個線程來執行這一系列的操作,因爲MySQL 爲了保證數據的一致性,操作的時候必須緩存池加鎖,一次只能有一個線程獲取到鎖

這個時候,大家這時候肯定滿腦子問號。串行那還談什麼效率?大家別忘記了,這一系列的操作都是在內存中操作的,實際上這是一個瞬時的過程,在內存中的操作基本是幾毫秒的甚至微妙級別的事情。

但是話又說回來,串行執行再怎麼快也是串行,雖然不是性能瓶頸,這還有更好的優化辦法嗎?那肯定的 MySQL早就設計好了這些規則。那就是 Buffer Pool 是可以有多個的,可以通過 MySQL的配置文件來配置,參數分別是:

# Buffer Pool 的總大小
innodb_buffer_pool_size=8589934592
# Buffer Pool 的實例數(個數)
innodb_buffer_pool_instance=4

一般在生產環境中,在硬件不緊張的情況下,建議使用此策略。這個時候大家是不是又會有一個疑問(如果沒有那說明你沒認真思考哦),大家應該有這樣的疑問:

# 問:多個 Buffer Pool 所帶來的問題思考
在多個線程訪問不同的 Buffer Pool 那不同的線程加載的數據必然是在不同的 Buffer Pool 中,假設 A 線程加載數據頁A到 Buffer Pool A 中,B 線程加載數據頁B到 Buffer Pool B 中,然後兩個都執行完了,這個時候 C 線程來了,他到達的是 Buffer Pool B中,但是 C 要訪問的數據是在 Buffer Pool A中的數據頁上了,這個時候 C 還會去加載數據頁A嗎?這種情況會發生嗎?在不同的 Buffer Pool 緩存中會去緩存相同的數據頁嗎?

# 答:多個 Buffer Pool 所帶來的問題解答
這種情況很顯然不會發生,既然不會發生,那 MySql 是如何解決這種問題的?其實前面已經提到過了,那就是 數據頁緩存哈希表(看下圖),裏面存放的是表空間號+數據頁號 = 緩存頁地址,所以 MySQL 在加載數據所在的數據頁的時候根據這一系列的映射關係判斷數據頁是否被加載,被加載到了那個緩存頁中,所以 MySQL 能夠精確的確定某個數據頁是否被加載,被加載的到了哪個緩存頁,絕不可能出現重複加載的情況。

 

 

12、動態調整 Buffer Pool 的大小

到此爲止,本文已經詳細的介紹了 Buffer Pool 的內存結構,它的數據是如何存放的,如何刷磁盤的,又是如何加載的,以什麼樣的形式存在的等等知識點,下面我們繼續挖掘,將 Buffer Pool 的相關知識點一次說個夠。我們現在來討論下 Buffer Pool 的大小能否動態調整。

假設我們現在的 Buffer Pool 的大小是 2GB大小,現在想將其擴大到 4GB,現在說一下如果真的要這麼做,我們的 MySql 需要做哪些事情。首先 ,MySQL 需要向操作系統申請一塊大小爲 4G 的連續的地址連續的內存空間,然後將原來的 Buffer Pool 中的數據拷貝到新的 Buffer Pool 中。

這樣可能嗎?如果原來的是8G,擴大到 16G,那這個將原來的數據複製到新的 Buffer Pool 中是不是極爲耗時的,所以這樣的操作 MySQL必然是不支持的。但實際上這樣的需求是客觀存在的,那 MySQL是如何解決的呢?

爲了處理這種情況,MySQL設計出 chunk (http 協議中也有使用到這個思想,所以我們會發現很多技術的優秀思想都是在相互借鑑)機制來解決的

# 什麼是chunk機制
chunk是 MySQL 設計的一種機制,這種機制的原理是將 Buffer Pool 拆分一個一個大小相等的 chunk 塊,每個 chunk 默認大小爲 128M(可以通過參數innodb_buffer_pool_chunk_size 來調整大小),也就是說 Buffer Pool 是由一個個的chunk組成的

假設 Buffer Pool 大小是2GB,而一個chunk大小默認是128M,也就是說一個2GB大小的 Buffer Pool 裏面由16個 chunk 組成,每個chunk中有自己的緩存頁和描述數據,而 free 鏈表、flush 鏈表和 lru 鏈表是共享的

 

 如果說有多個 Buffer Pool ,那就是這樣

 

 

說到這裏好像還是沒有說到 MySQL到底是如何通過 chunk 機制來調整大小的。實際上是這樣的,假設現在 Buffer Pool 有 2GB,裏面有16個chunk,現在想要擴大到 4GB,那麼這個時候只需要新申請一個個的 chunk 就可以了。

這樣不但不需要申請一塊很大的連續的空間,更不需要將複製數據。這樣就能達到動態調整大小了(不會還有人問:這只是擴大,怎麼縮小呢?)。不得不說 MySQL真機智。

 

13、生產環境如何設置 Buffer Pool 大小

Buffer Pool 是不是越大越好,理論上是的。那如果一個機器內存是16GB那分配給 Buffer Pool 15GB,這樣很顯然是不行的,因爲操作系統要佔內存,你的機器上總會運行其他的進行的吧?那肯定也是需要佔用內存的。根據很多實際生產經驗得出的比較合理的大小是機器內存大小的(50%~60%)

最後一起來看看你的 INNODB 的相關參數,命令是show engine innodb status

 

show engine innodb status;

----------------------
 Buffer Pool  AND MEMORY
----------------------
--  Buffer Pool 的最終大小
Total memory allocated
--  Buffer Pool 一共有多少個緩存頁
 Buffer Pool  size
-- free 鏈表中一共有多少個緩存也是可以使用的
Free buffers        
-- lru鏈表中一共有多少個緩存頁
Database pages 
-- lru鏈表鏈表中的冷數據區一共有多少個緩存頁
Old database pages  
-- flush鏈表中的緩存頁的數量
Modified db pages     
-- 等待從磁盤上加載進來的緩存頁的數量
Pending reads 
-- 即將從lru鏈表中刷入磁盤的數量,flush鏈表中即將刷入磁盤的緩存頁的數量
Pending writes: LRU 0, flush list 0, single page 0
-- lru鏈表的冷數據區的緩存頁被訪問之後轉移到熱數據區的緩存頁的數量,以及冷數據區裏1s之內被訪問但是沒有進入到熱數據區的緩存頁的數量
Pages made young 260368814, not young 0
-- 每秒從冷數據轉移到熱數據區的緩存頁的數量,以及每秒在冷數據區被訪問但是沒有進入熱數據區的緩存頁的數量
332.69 youngs/s, 0.00 non-youngs/s
-- 已經讀取創建和寫入的緩存頁的數量,以及每秒讀取、創建和寫入的緩存頁的數量
Pages read 249280313, created 1075315, written 32924991 359.96 reads/s, 0.02 creates/s, 0.23 writes/s
-- 表示1000次訪問中,有多少次是命中了BufferPool緩存中的緩存頁,以及每1000次訪問有多少數據從冷數據區轉移到熱數據區,以及沒有轉移的緩存頁的數量
 Buffer Pool  hit rate 867 / 1000, young-making rate 123 / 1000 not 0 / 1000
-- lru鏈表中緩存頁的數量
LRU len: 8190
-- 最近50s讀取磁盤頁的總數,cur[0]表示現在正在讀取的磁盤頁的總數
I/O sum[5198]:cur[0],

  

14、結束語

本篇文章我們詳細討論了 Buffer Pool 的內存結構,從 free 鏈表到 lru 鏈表,從 Buffer Pool 到 chunk,從磁盤中加載一個數據頁到 Buffer Pool 到最後該數據頁又被刷回到磁盤中的一整個過程,他的每一步都做了什麼。

我們一起討論完本文以後,是不是瞬間有種看透來了 MySQL的感覺,但是這個僅僅是前提,學習這些的目的是爲了更好的理解 MySQL讓我們能夠在工作中更加遊刃有餘地使用它。因爲只有在知道了底層原理的情況下,才能熟悉他的工作原理,遇到問題才能對症下藥。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章