主機內存只有100G,現在對一個200G的大表進行掃描,會不會把數據庫的內存用完。
對大表做全表掃描對Sever層的影響
假設現對一個200G的InnoDB表db1,做一個全表掃描,當然要把掃描結果保存到客戶端。
InnoDB的數據時保存在主鍵索引上的,所以全表掃描實際上是掃描表t的主鍵索引,最后返回給客戶端。
返回的結果集并不是完整的,因為MySQL是邊讀邊發的
流程為:1.獲取一行寫到net_buffer當中,net_buffer是由net_buffer_length定義的,默認為16k。
???????????????2.重復獲取知道net_buffer寫滿,調用網絡接口發送出去。
???????????????3.若是發送成功,就清空net_buffer,然后繼續讀取下一行寫入net_buffer
???????????????4.若發送函數返回EAGAIN或WSAEWOULDBLOCK就表示本地網絡棧寫滿,直到網絡棧重寫可寫,再繼續重復操作。
一個查詢在發送過程當中,占用MySQL內部最大內存就是net_buffer這么大,并不會達到200G。這意味著,若客戶端接收慢,MySQL就會由于結果發送不出去導致事務執行的時間變長。
若是客戶端不讀socket receive buffer中的內容,然后再show processlist中可以看到state處于一個Sending to client的狀態。
對于線上業務來說,若是一個查詢的返回結果不會很多,就可以在客戶端使用一個-quick參數就可以使用,mysql_use_result這個方法,讀一行處理一行。當然前提是查詢返回結果不多,若是看到多個線程都處于Sending to client,可以將net_buffer_length設置為一個更大的值。
Sending data
MySQL查詢語句在進入執行階段之后,首先將狀態設置為Sending data,再繼續執行語句的流程,執行完成后就會將狀態改為空字符串。
也就是說在一個線程處于“等待客戶端的狀態”才會顯示未Sending to client,Sending data是正在執行。
全表掃描對InnoDB的影響
InnoDB內存的作用是保持更新結果在配合redo log避免了隨機寫盤,內存的數據頁是在BUffer Pool中管理的。
BUffer Pool還有一個加速功能,因為有WAL機制,當時事務要提交的時候,有一個查詢要讀該內存頁,就可以直接讀,因為這個時候,內存頁是最新的,直接讀內存頁就可以了,無需將redo log應用到數據頁當中再讀取。
Buffer Pool對于查詢加速效果還有一個重要的指標:內存命中率,一般情況下,內存命中率要在99%以上。
InnoDB Buffer Pool大小是由參數innodb_buffer_pool_size決定的,一般設置為物理內存的60%-80%。
innodb_buffer_pool_size小于磁盤的數據量很常見,若一個buffer pool滿了,就要淘汰一個舊數據頁來更新一個新數據頁。InnoDB通過改進LRU算法來實現這一目標。
LRU算法:假設內存當中有P1,P2,P3,P4,P5這么多數據頁,是以鏈表形式保存的,P1是剛剛更新的所以在頭部,這個時候有請求訪問P3,P3就會被移動到頭部,現在要更新一個數據頁,因為內存滿了,要刪除一個,就會刪除尾巴的P5數據頁。
InnoDB改進:InnoDB將其進行改進,以5:3將空間分為young和old區域,young區域中的操作和原LRU算法相同。
在old區域每次被訪問的時候做如下的操作:
1.若這個數據頁在LRU鏈表中存在時間超過1秒,就移動到頭部。
2.若是短于1秒,位置保持不變
時間有參數Innodb_old_blacks_time控制,單位為毫秒,默認一秒。