Mysql InnoDB Buffer Pool( 二 )

預讀導致加載到buffer pool中頁的不一定會使用到

  • 全表掃描語句
    當一個sql沒有合適的索引或者沒用where限定條件的時候,innodb會掃描該表聚集索引所有的頁 。如果頁非常多,buffer pool無法容納的時候 , 就會把其他有用的緩沖頁進行淘汰,降低緩存命中率 。全表掃描導致許多使用頻率低的頁被同時加載到buffer pool中 , 導致使用頻率高的頁從buffer pool中被移除(這里可以看出LFU算法的好處,哈哈哈)
  • 3.innodb 如何解決預讀和全表掃描導致緩存命中率降低的問題innodb 根據一定比例將LRU鏈表分為兩部分:
    • 熱數據區:使用頻率很高的緩沖頁構成,稱為young區
    • 冷數據區:使用頻率不是很高的緩存頁構成 , 稱為old區

    Mysql InnoDB Buffer Pool

    文章插圖
    innodb_old_bolocks_pet可以設置old區占用的比列,默認是37%
    3.1解決預讀頁面后續也許使用不到的問題innodb規定當磁盤某個頁面在初次加載到buffer pool中某個緩沖頁時,該緩沖頁對應的控制塊會放在old區域的頭部,這樣預讀到的且后續如果不進行后續訪問的頁面會逐漸從old區移除,而不影響young區使用頻率高的緩沖頁 。
    3.2解決全表掃描短時間訪問大量使用頻率低頁面的問題在進行全表掃描時,雖然首次訪問放在old區頭部,但是后續會馬上被訪問到,這時候會把該頁放在young區域的頭部,這樣依舊會影響到使用頻率高的頁面 。
    為了解決這個問題,innodb規定對于某個處于old區的緩沖頁第一次訪問時 , 就在其控制塊中記錄下訪問時間,如果后續訪問的時間和第一次訪問的時間,在某個時間訪問間隔內(innodb_old_blocks_time可以進行設置)那么頁面不會從old區移動到young區,反之移動到young區中 。這個時間間隔默認時1000ms,基本上多次訪問同一個頁面中的多個記錄的時間不會超過1s 。
    3.3 優化每次都需要移動young區節點到LRU鏈表頭部的問題如果每次訪問一個緩沖頁都需要移動到LRU鏈表的頭部,像young區中這種熱點數據 , 每次都需要更新鏈表頭部,并且這還是一個高并發操作,需要CAS或者鎖,開銷也不小 。為了解決這個問題 innodb規定只有被訪問的緩沖頁位于young區的前1/4范圍外,才會進行移動,所以前1/4的高熱度的數據,不會頻繁移動
    六丶臟頁刷盤innodb后臺有專門的線程負責將臟頁刷新到磁盤
    • 從LRU鏈表中的冷數據刷新一部分頁面到磁盤
      后臺線程定時從LRU鏈表尾部掃描一些頁面,掃描的頁面數量可以通過innodb_lru_scan_depth指定,如果在LRU中發現臟頁,那么刷新到磁盤
    • 從flush鏈表刷新一部分頁面到磁盤
      后臺線程也會定時從flush鏈表中刷新一部分頁面到磁盤,刷新速率取決于系統是否繁忙
    如果后臺線程刷新的很慢,且有新的頁面需要進行緩存,這時候會從LRU鏈表尾部看看是否有可以直接釋放的非臟頁,如果不存在那么需要刷盤然后緩存新的頁 。
    這里我們可以看到buffer pool沒用保證修改的數據一定被磁盤持有化 , 那么事務的持久性如何實現昵,怎么保證mysql服務突然掛了,已經提交的事務不會丟失昵,這就得提到redo log了七丶多個buffer pool實例在并發量比較大的時候,多個線程操作同一個buffer pool,必然涉及到同步機制,影響到請求的處理速度 , 所以在buffer pool比較大的時候,會被拆分成多個小的buffer pool,獨立進行使用,在高并發的時候不會相互影響(雖然也不能公用彼此的緩存內容)提高并發處理能力 。只有在innodb_buffer_pool_size設置的buffer pool大小大于1g的時候 , 通過innodb_buffer_pool_instances設置的buffer pool實例個數才會生效
    八丶動態的擴大縮小buffer pool為了能夠在運行的時候動態的擴大縮小buffer pool,innodb提出chunk的概念,innodb 不在一次申請為某一個buffer pool申請一大片連續的內存空間,而是以chunk作為單位進行申請 。一個chunk就是一個連續的內存空間,其內部包含了若干緩沖頁和其對應的控制塊 。
    Mysql InnoDB Buffer Pool

    文章插圖
    可以通過innodb_buffer_pool_chunk_size設置每一個chunk的大?。?默認時128mb 。
    所以我們最好讓innodb_buffer_pool_size = innodb_buffer_pool_chunk_size x innodb_buffer_pool_instances的若干倍保證每一個buffer pool實例中chunk數相同,如果

    推薦閱讀