学习笔记:InnoDB存储结构及多版本实现
因為InnoDB是多版本化的數據庫存儲引擎, 它必須在表空間中保存關于舊版本數據行的信息。這個信息被存在名為rollback segment(類似于Oracle中的回滾段)的數據結構中。
在內部,InnoDB給數據庫中的每一行添加三個域。一個是6字節的DB_TRX_ID域,用來說明插入或更新該行的最后一個事務的事務識別符。同時,刪除操作也被內部處理為更新操作,其中行中一個特殊的位被設置用來標注該行已刪除。每一行也包含一個稱為回滾指針的7字節DB_ROLL_PTR域。回滾指針指向一個寫在回滾段中的撤銷日志記錄。如果該行被更新,撤銷日志記錄包含重建該行被更新之前的內容必需的信息。還有一個6字節的DB_ROW_ID域包含在新行被插入時單調增加的Row ID,如果InnoDB自動生成聚集索引,索引中就會包含這個Row ID。否則,這個DB_ROW_ID不會出現在任何索引中。
InnoDB使用在回滾段中的信息來執行事務回滾中需要的撤銷操作。它也使用這個信息來為一個持續讀構建數據行的早期版本。
在回滾段中的撤銷日志被分為插入和更新兩種。插入撤銷日志僅在事務回滾中需要,且只要事務一提交就可以被丟棄。更新撤銷日志也被用在持續讀中,而且它們僅在沒有被InnoDB分配給一個事務快照之后才能被丟棄,因為這個快照在持續讀中可能會需要撤銷日志的信息來建立一個數據行的早期版本。
你必須記得有規律地提交你的事務,包括那些只包含持續讀的事務。否則, InnoDB不能從更新撤銷日志丟棄數據,并且回滾段可能變得太大,填滿你的表空間。
在一個回滾段里,一個撤銷日志記錄的物理尺寸小于相應的已插入行或已更新行。你可以用這個信息來計算回滾段需要的空間。(如果是插入,那么記錄那個行的id號到回滾段就ok了,如果要刪除,直接通過id號來定位行即可刪除它,實現回滾.如果是一般的更新,那么直接記錄對應的行id和被更新的字段即可.但是如果是刪除操作,innodb只需要存儲一條刪除日志到回滾段中,比如只包含rowid信息,回滾的時候,只需要把對應的rowid的標記位deleted刪除即可.)
在InnoDB多版本化方案中,當你用SQL語句刪除一行時,該行沒有被從數據庫立即物理刪除掉。只有當InnoDB可以丟棄用于刪除操作的撤銷日志記錄時,InnoDB才從數據庫物理刪除相應行以及它的索引記錄。這個刪除操作被成為凈化(Purge,有點類似于Postgresql中的autovacuum),它運行得很快,通常與做刪除的SQL語句花的時間在一個數量級。(這種方式還是非常先進的,理由有2: a.對于刪除操作,完全可以把刪除的行全部移動到回滾日志中,而不是標記為刪除.當需要回滾的時候,直接把這些行執行插入操作即可回滾;而需要提供一致讀的時候,直接去回滾段中查找即可----這顯然浪費了大量的IO,所以innodb不這么做. b.這種做法還節省了磁盤空間.試想如果把刪除的信息都存儲到回滾段中,一個delete * from t該要產生多少回滾日志?浪費多少磁盤空間?而且當事務回滾的時候,把這些東西從回滾段拷貝到磁盤,又是多么浪費時間? 當回滾段被重用的時候,innodb會先刪除回滾日志中的條目,然后把這些回滾日志指向的被標記為deleted的行也purge掉. oracle的做法是刪除的時候將整行數據放入回滾段,所以oracle中事務回滾的成本是很高的)
在某種情景下,用戶以幾乎相同的比率,小批次地在表中插入和刪除行,凈化線程可能會滯后,并且表變得越來越大,所有操作都由于磁盤約束變得非常慢。即使表只有10MB有用的數據,它也可能被死行占據10GB空間。在這種情況下,節流新操作,并分配更多的資源來凈化線程會比較好。全局系統變量innodb_max_purge_lag就是為此而生的。
轉載于:https://www.cnblogs.com/seawwh/archive/2012/01/13/2322127.html
總結
以上是生活随笔為你收集整理的学习笔记:InnoDB存储结构及多版本实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (转)网站推广优化教程100条(SEO,
- 下一篇: Django Tips