1. 程式人生 > >mysql內存數據淘汰機制和大查詢會不會把內存打爆?

mysql內存數據淘汰機制和大查詢會不會把內存打爆?

.net 返回 用戶 鏈表 sql查詢 順序 rom 重新 效果

首先我們說一下大查詢會不會把內存打爆?

比如說主機內存有5g,但是我們一個大查詢的數據有10g,這樣會不會把內存打爆呢?

答案:不會

為什麽?

因為mysql讀取數據是采取邊讀邊發的策略

select * from t1

這條語句的流程是這樣的

技術分享圖片

1.讀取數據放入net_buffer中,net_buffer大小是由net_buffer_length控制

2.net_buffer放滿了以後,調用網絡棧發送數據到客戶端

3.如果發送成功就清空net_buffer,繼續讀取數據放入net_buffer中

4.如果發送函數返回EAGAIN或者WSAEWOULDBLOCK就表示本地網絡棧滿了,這時候就進入等待,知道網絡棧重新可寫,再繼續發送。

根據這個流程來看,讀取數據的時候占用的內存最多也就是net_buffer的大小。

InnoDB內存(buffer pool)管理

我們都知道mysql查詢數據是先看內存中有沒有數據,如果沒有就從磁盤中讀出來,然後在讀入內存

所以說bufferpool對查詢有加速效果,加速效果依賴於一個指標也就是內存命中率,如果命中率能達到100%那是最好的

通過

show engine innodb status

可以查看命中率

innodb buffer pool的大小是由參數innodb_buffer_pool_size控制的,一般設置為可用物理內存的60%-80%

內存淘汰

既然內存是一塊固定大小的,那麽存放在內存裏的數據就肯定有的會被淘汰

下面是一個lur算法的基本模型

技術分享圖片

innodb管理bufferpool的lru算法是基於鏈表實現的

state1:我們要查詢p3的數據,由於p3是在內存中的,那麽久直接把p3移動到鏈表頭部,

也就是對應圖中state2的狀態

state3中由於我們查詢的px數據不是在px中,那麽就從磁盤中查詢出px的數據放入鏈表頭部,

但是由於內存滿了,所以

就會把pm的數據從鏈表尾部淘汰掉,從現象上來看就是最久沒有被訪問都的數據會被淘汰

這種算法對於mysql來說有什麽問題??

如果我們對一個冷數據表進行全表掃描,比如說日誌表,這些不是正常用戶訪問的表,

那麽在bufferpool中就會大量存在這些數據的表,那麽就會導致用戶正常訪問存放的業務數據會被淘汰掉,

就會導致大量數據需要重新讀磁盤放入內存,這樣性能就會大大降低

mysql肯定不會允許這種情況發生的,所以它基於上面的lru算法做了改進

下圖就是改進後的模型

技術分享圖片

innodb把整個內存的前八分之五記為young區域,後八分之三記為old區域,

我們看上圖state1中由於我們訪問的p3是在young區域,那麽就把p3移動到鏈表頭部

但是如果我們訪問的數據如果是在old區域,比如說我們訪問了px,這個時候會做個判斷

如果px在內存中存活時間超過1秒,就會把它移動到young區域的鏈表頭部,否則位置不動

這個1秒是由參數

innodb_old_blocks_time控制的,默認值是1000,單位毫秒

這樣我們在看掃描全表的步驟

掃描過程中被訪問的數據頁會被放在old區域

一個數據頁有多條記錄會被訪問,所以這數據頁會被多次訪問到,但是由於是順序掃描,

這個數據頁第一次被訪問和最後一次被訪問的時間間隔不會超過一秒,所以就會一直在old區域

在繼續掃描後面的數據頁,之前的這個數據頁也不會被訪問到,因此就會一直在old區域,也就很快就會被淘汰掉了

可以看到這個策略的最大收益,就是在掃描的過程中,雖然也用到了bufferpool,

但是不會對young區域造成影響,也就保證了bufferpool響應業務的內存命中率

mysql內存數據淘汰機制和大查詢會不會把內存打爆?