Mysql

為什麼 InnoDB 將所有數據庫儲存在一個文件中?

  • September 6, 2017

MyISAM 用來將每個表儲存在相應的文件中很方便。InnoDB 在很多方面都取得了進步,但我想知道為什麼 InnoDB 將所有數據庫儲存在一個文件中(ibdata1預設情況下)。

我知道 InnoDB 將通過表的各個索引文件映射文件中數據的位置,但我不明白為什麼它將所有數據混合在一個文件中。更重要的是,為什麼要混合伺服器上所有數據庫的數據?

MyISAM 的一個有趣特性是可以將數據庫文件夾複製/粘貼到另一台機器上,然後使用該數據庫(無需轉儲)。

InnoDB 的架構需要使用四種基本類型的資訊頁面

  • 表數據頁

  • 表索引頁

  • 表元數據

  • MVCC數據(支持事務隔離和ACID 合規性

    • 回滾段
    • 撤消空間
    • 雙寫緩衝區(後台寫入以防止依賴作業系統記憶體)
    • 插入緩衝區(管理對非唯一二級索引的更改)

請參閱 ibdata1 的圖示

預設情況下,innodb_file_per_table被禁用。這會導致所有四種資訊頁麵類型都登陸一個名為 ibdata1 的文件。許多人試圖通過製作多個 ibdata 文件來分散數據。這可能導致數據和索引頁面的碎片化。

這就是為什麼我經常建議清理 InnoDB 基礎設施,使用預設的 ibdata1 文件,僅此而已

由於 InnoDB 工作的基礎設施,複製是非常危險的。有兩個基本的基礎設施

  • innodb_file_per_table 已禁用
  • 已啟用 innodb_file_per_table

InnoDB(禁用innodb_file_per_table )

禁用innodb_file_per_table後,所有這些類型的 InnoDB 資訊都存在於 ibdata1 中。ibdata1 之外的任何 InnoDB 表的唯一表現形式是 InnoDB 表的 .frm 文件。一次複製所有 InnoDB 數據需要複製所有 /var/lib/mysql。

複製單個 InnoDB 表是完全不可能的。您必須通過 MySQL 轉儲來提取表的轉儲作為數據及其相應索引定義的邏輯表示。然後,您將該轉儲載入到同一伺服器或另一台伺服器上的另一個數據庫。

InnoDB(啟用innodb_file_per_table )

啟用innodb_file_per_table,表數據及其索引位於 .frm 文件旁邊的數據庫文件夾中。例如,對於表 db1.mytable,該 InnoDB 表在 ibdata1 之外的表現形式將是:

  • /var/lib/mysql/db1/mytable.frm
  • /var/lib/mysql/db1/mytable.ibd

系統表空間ibdata1

db1.mytable 的所有元數據仍駐留在 ibdata1中,絕對沒有辦法解決這個問題。重做日誌和 MVCC 數據也仍然存在於 ibdata1 中。

當涉及到表碎片時,ibdata1 會發生以下情況:

  • 啟用innodb_file_per_tableALTER TABLE db1.mytable ENGINE=InnoDB; :您可以使用或縮小 db1.mytablesOPTIMIZE TABLE db1.mytable;。這導致 /var/lib/mysql/db1/mytable.ibd 在物理上更小,沒有碎片。
  • innodb_file_per_table disabled:您不能使用 db1.mytables 來縮小它,ALTER TABLE db1.mytable ENGINE=InnoDB;因為OPTIMIZE TABLE db1.mytable;它與 ibdata1 一起存在。實際執行任一命令,使表連續並更快地讀取和寫入。不幸的是,這發生在 ibdata1 的末尾。這使得 ibdata1 快速增長。這在我的 InnoDB Cleanup Post 中得到了充分解決

警告(或機器人在迷失太空中所說的危險)

如果您只想複製 .frm 和 .ibd 文件,那麼您將陷入痛苦的世界。***僅當且僅當您可以保證 .ibd 文件的表空間 id 與 ibdata1 文件的元數據中的表空間 id 條目完全匹配時,***複製 InnoDB 表的 .frm 和 .ibd 文件才有效。

我在 DBA StackExchange 上寫了兩篇關於這個表空間 id 概念的文章

這是一個很好的連結,關於如何在表空間 id 不匹配的情況下將任何 .ibd 文件重新附加到 ibdata1:http: //www.chriscalender.com/ ?tag=innodb-error-tablespace-id-in-file 。閱讀本文後,您應該立即意識到複製 .ibd 文件簡直是瘋了。

對於 InnoDB,你只需要這個來移動

CREATE TABLE db2.mytable LIKE db1.mytable;
INSERT INTO db2.mytable SELECT * FROM db1.mytable;

製作 InnoDB 表的副本。

如果要將其遷移到另一個數據庫伺服器,請使用 mysqldump。

關於混合來自所有數據庫的所有 InnoDB 表,我實際上可以看到這樣做的智慧。在我雇主的數據庫/Web 託管公司,我有一個 MySQL 客戶端,它在一個數據庫中有一個表,其約束映射到同一個 MySQL 實例中另一個數據庫中的另一個表。通過一個通用的元數據儲存庫,它使跨多個數據庫的事務支持和 MVCC 可操作性成為可能。

引用自:https://dba.stackexchange.com/questions/15531