多朋友可能會有許多關于Innodb如何使用內存的問題。我這里將簡單介紹一下innodb內存結構,然后以innodb啟動時的分配情況做一個解釋。
1、INNODB內存結構
1.1、聚集索引與非聚集索引:
聚集索引:主鍵,有序,存儲順序與內存一致 非聚集索引:非主鍵,無序 聚集索引在葉子節點存儲的是表中的數據 非聚集索引在葉子節點存儲的是主鍵和索引列 使用非聚集索引查詢出數據時,拿到葉子上的主鍵再去查到想要查找的數據。(拿到主鍵再查找這個過程叫做回表)
1.2、緩沖池:
緩沖池用于存放各種數據的緩存。Innodb總是將磁盤中的數據(數據庫文件)按頁(16K)讀取到緩沖池,然后按最近最少使用算法(LRU)來保存緩沖池中的數據。如果數據庫 文件需要修改,總是先修改在緩存池中的頁(發生修改后,該頁為臟頁),然后按一定頻率刷新到磁盤中。
1.3、insert buffer(插入緩沖):
使用條件:1.索引是輔助索引;2.索引不是唯一的。 也就是說,主鍵索引不使用插入緩沖。主鍵索引是聚集索引,插入是順序的,執行效率比較高,就不借助緩沖了。 但是,當表中存在輔助索引(非聚集索引,非主鍵)時,不一定是順序的了,這時需要離散的訪問,插入性能會降低。 所以,對于非聚集索引的插入和更新操作,不是直接插入到索引頁中,而是插入到緩沖中,再以一定頻率執行插入緩沖和非聚集索引葉子節點的合并操作。 注:由于非主鍵索引葉子節點存的是主鍵和當前列值,所以使用非聚集索引查詢時,先查輔助索引的那顆樹找到對應的主鍵,再查主鍵索引的那顆樹,會查兩次,效率不高。
1.4、redo log(重做日志):
在事務提交的時候,Innodb會先把數據從磁盤中讀到內存進行修改,然后把事務日志寫到日志緩沖(log buffer),然后再刷新到重做日志文件(redo log file)中進行持久化, 然后再定期刷新到磁盤中。 用于在實例故障恢復時,繼續那些已經commit但數據尚未完全回寫到磁盤的事務。
1.5、double write(兩次寫):
為防止redo log在寫的過程中損壞,我們需要留個備份。若出現故障,先從備份中恢復redo log,再進行數據恢復。
1.6、undo log:
記錄數據修改前的鏡像,用于將未提交的事務回滾到事務開始前的狀態。 undo操作:當Innodb存儲引擎回滾時,它實際上做的是與之前相關的工作,對于insert操作,Innodb會完成一個delete,對于update,則會執行一個相反的update,將修改 前的行放回去。
1.7、自適應哈希索引:
Innodb會監控表上索引的查找頻率,若發現建立哈希索引會提升速度,則自動創建哈希索引。不是對整張表建立索引,而是根據訪問頻率對某些頁建立。
1.8、事務提交:
事務進行過程中,每次sql語句執行,都會記錄undo log和redo log,然后更新數據形成臟頁。然后redo log按照時間或空間等條件進行落盤,undo log和臟頁按照checkpoint 進行落盤,落盤后相應的redo log就可以刪除了。此時,事務還未commit,如果發生崩潰,則首先檢查checkpoint記錄,使用相應的redo log進行數據和undo log的恢復,然后 查看undo log的狀態發現事務尚未提交,然后就使用undo log進行回滾。事務執行commit操作時,會將本事務相關的所有redo log都進行落盤,只有所有redo log落盤成功, 才算commit成功。然后內存中的數據臟頁繼續按照checkpoint進行落盤。如果此時發生了崩潰,則只使用redo log恢復數據。
2、一些重要的概念:
NBLOCKS=Innodb_buffer_pool有多個頁(block)=innodb_buffer_pool_size/16384(16k)
OS_THREADS= if ( innodb_buffer_pool_size >= 1000Mb) = 50000
else if (innodb_buffer_pool_size >= 8Mb) = 10000
else = 1000 (該值只用在*nixes系統上,對于windows有一點小的區別計算OS_THREADS)
3、Innodb 使用的內存包括:
- innodb_buffer_pool_size
- innodb_additional_mem_pool_size
- innodb_log_buffer_size
- adaptive index hash ,size (innodb buffer 索引管理區)= innodb_buffer_pool_size/64
- system dictionary hash,size(innodb內部字典區) = 6 * innodb_buffer_pool_size/512
- memory for sync_array,size(用于Innodb內部syncronzation的開銷)=OS_THREAD * 512
- memory for os_event,size(用于innodb內存的syncronzation的開銷)=OS_THREAD * 216
- memory for locking system(內存的鎖管理系統),size = 5 * 4 *NBBLOCKS
4、innodb內存使用的計算公式為:
Innodb_buffer_pool_size + innodb_log_buffer_size + innodb_additional_mem_pool_size + 812/16384 * innodb_buffer_pool_size + OS_THREADS * 368
對于812/16384 * Innodb_buffer_pool_size 可以簡單的用 innodb_buffer_pool_size / 20 計算,
對于OS_THREADS * 368
OS_THREADS * 368 = 17.5 MB if innodb_buffer_pool_size > 1000MB OS_THREADS * 368 = 3.5 MB if innodb_buffer_pool_size > 8MB
舉一個例子:
如果你的innodb_buffer_pool_size有1500MB,innodb_additional_mem_pool_size =20 MB,innodb_log_buffer_size = 8M,
Innodb 將會向系統申請內存為= 1500M + 20M + 8M + 1500/20 M +17.5 = 1620.5M
根據以上的條件可以算出Innodb最根本最需要多少內存,這樣對于服務器的內存使用也可以有一個規劃了。