Mysql 百問系列:Buffer Pool 是什麼?

Mysql 百問系列:Buffer Pool 是什麼?

問題背景知識若是沒有Buffer Pool ,那麼查詢流程會如何?Buffer Pool 如何提升寫的效率的髒頁存在的價值?頁的替換規則因此要淘汰哪些頁面呢?結語mysql

問題

  1. 爲何會須要 Buffer Pool ?
  2. Buffer Pool 爲何能提升讀寫效率?
  3. 什麼是緩存命中?

背景知識

在講解Buffer Pool 以前須要知道一些背景知識:web

  1. InnoDB 類型的存儲引擎是會把數據寫到磁盤上的。(Mysql 5.6.6 之後默認) InnoDB 以表爲單位,生成 表名.frm 和 表名.idb 文件 存儲在相應的Mysql存儲目錄下。
  2. InnoDB 是以 頁(通常爲大小爲16K) 爲單位,從磁盤文件中讀取數據 到內存的。 一頁 包含多條記錄(每頁至少要有2條記錄)。 記錄有更新也是以頁爲單位刷新到磁盤中。每一頁中的記錄都是按照索引 大小順序排序。

若是沒有Buffer Pool ,那麼查詢流程會如何?

讓咱們來模擬一個簡單的場景,假設有個表school , 其中有1000條數據,如今執行查詢redis

select  * from school where id = 400
複製代碼

咱們須要獲取 id 爲400的學校全部信息。算法

  1. 那麼InnoDB 須要先找到 id =400 這條記錄所在的頁,把這頁讀取到內存,而後從這頁的全部記錄中找到id=400那條記錄返回。
  2. 輸出結果到客戶端,釋放內存。

查詢完id =400 後,又來了一條查詢語句:sql

select  * from school where id = 401
複製代碼

因而Innodb 又得按照上面流程再走一遍, 從磁盤中找到對應的頁面,放到內存, 找到結果釋放內存。
那麼分析上面的過程,咱們能夠知道每次搜索都會進行磁盤IO,而磁盤IO的速度相對於CPU,內存的計算速度是遠遠不及的。
爲了避免每一次搜索都須要進行磁盤IO, 那麼InnoDB 引入了 Buffer Pool 來充當緩存``
因此查詢流程就變爲:數據庫

  • 先在Buffer Pool中查找 id= 400 這條記錄所在的頁,若是該頁存在,則直接查詢到記錄返回,若是該頁不存在,則從磁盤進行讀取,放入Buffer Pool,返回記錄。

(這個過程就是咱們平時使用redis充當緩存的過程。先判斷某個key 存不存在,若是存在則讀取記錄返回,若是不存在,則查詢數據庫,將記錄存放到redis ,返回記錄。)緩存

Buffer Pool 的功能就是 緩存「頁」 ,減小磁盤IO,提升讀寫效率。app

Buffer Pool 如何提升寫的效率的

如今咱們須要給某個學習修更名稱,假設原來 id=400 的學校名稱爲 「aa"學習

update school set name = 'xs' where id = 400
複製代碼

更新語句的流程爲:spa

  1. 查找 數據頁 是否在Buffer Pool 中,若是存在,直接更新內存。不存在則從磁盤讀取數據到Buffer Pool 中,而後更新。 (這過程其實還涉及到表是否存在非惟一索引,以及change buffer。 )
  2. 將更新內容寫入redo log (什麼是redo log ? 它是作什麼用的?挖個坑之後填。)

從上面流程中發現一個問題沒有, 咱們知道Buffer Pool 是一塊內存空間,咱們修改了Buffer Pool 中的記錄,可是並無把記錄從新寫回到磁盤文件中。也就是說此時磁盤中記錄的信息 和 Buffer Pool 中記錄的信息是不一致的。
例子中 這個時候 磁盤中id=400 對應的記錄學校名稱仍是"aa" ,而 Buffer Pool 中對應名稱則爲「xs"。

這種磁盤記錄的信息與Buffer Pool 記錄的信息不一致的頁, 稱爲髒頁



髒頁存在的價值?

這種磁盤和Buffer Pool 記錄信息不一致的狀況還會有價值? 咱們來想一下這種狀況,好比咱們須要批量更新一批數據。

update school set name = 'xs' where id > 400
複製代碼

這個時候會找到Buffer Pool中對應的頁,而後修改。 例子中600條記錄有大機率是存在在同一頁面中的。上面提到過頁中的記錄是按索引排序的,並且通常16K大小的頁,能存放的記錄數是幾百上千條。
因爲不是每一條記錄更改都會更新到磁盤,因此上面的更新語句大大節省了時間,畢竟寫數據到磁盤是十分耗時的。

固然髒頁也不可能一直存在在Buffer Pool 中,總要將信息刷新到磁盤中。否則若是程序出問題,或者機器斷電,更新的信息不就丟失了嘛。
那麼何時會把Buffer Pool 中的信息更新到磁盤中呢?

  • Mysql 會有專門的後臺線程,每隔一段時間就將髒頁 刷新到磁盤
  • Buffer Pool 空間不足, 髒頁將被淘汰 從 Buffer Pool 中移除的時候
  • redo log 寫滿的時候
  • 數據庫正常關閉的時候。

頁的替換規則

Buffer Pool 是一片內存空間,受制於內存空間大小。 能夠經過innodb_buffer_pool_size 來控制Buffer Pool 的大小。因此Buffer Pool 內存放的頁 數量也是有限的。假設Buffer Pool 中只能存放1000個頁,而且已經存滿。 那麼若是下一次查詢的記錄並不在這1000頁中,須要從磁盤讀取相應頁 加載到Buffer Pool 中。因爲Buffer Pool 已經滿了,因此必需要把其中某一個頁面先移除, 才能把新的頁面放進來。

因此要淘汰哪些頁面呢?

咱們知道若是查詢或者修改記錄,記錄的頁已經存在在Buffer Pool 中那麼將有效的提升效率。最理想的狀況是每次訪問頁面都已經存在在Buffer Pool 中,咱們稱爲 緩存命中。淘汰頁面的算法,對 緩存命中率 相當重要。
因爲Buffer Pool的緩存淘汰規則比較複雜,後面另開一篇進行講解。核心思想就是把最近最少使用的頁面淘汰,也就是 LRU (Least recently used)算法。

結語

  • Buffer Pool 是一塊內存空間。 將頁面加載到Buffer Pool 中能夠減小磁盤IO 提升查詢效率。
  • 每次更新先更新Buffer Pool 中的記錄,並將存放該記錄的頁標記爲 髒頁。後臺進程每隔一段時間刷新髒頁到磁盤提升磁盤IO效率。Buffer Pool的引入提高了讀寫效率。
  • 緩存命中率 體現了Buffer Pool的利用效率。Buffer Pool 經過LRU算法來淘汰頁面提升緩存命中率。

喜歡和支持,請關注下我的公衆號,謝謝。

相關文章
相關標籤/搜索