Ibdata1 是 InnoDB 存儲引擎之王——該文件保存了從 InnoDB 存儲引擎派生的數據、索引和元數據。 它是如何工作的? 我們可以做些什么來使我們使用存儲引擎的工作盡可能有效? 在這個博客中找到答案。
如果您在數據庫領域至少有一段時間,并且熟悉 MySQL 或其任何風格,您肯定會知道 InnoDB 是什么——它是 MySQL 提供的主要存儲引擎之一,也是默認引擎 自 2010 年發布 MySQL 5.5.5 以來,InnoDB 一直是存儲引擎。InnoDB 具有許多獨特的怪癖和獨特的特性——但最吸引人的可能是存儲引擎的主文件——ibdata1。
ibdata1 是整個 InnoDB 基礎設施的王者——該文件經常被稱為“表空間數據文件”,這是有充分理由的:該文件存儲與 InnoDB 相關的所有內容,包括但不限于:
基于 InnoDB 的表的數據和索引(如果啟用設置 innodb_file_per_table,則此事實不適用——即設置為“1”的值)
雙寫和插入緩沖區——雙寫緩沖區由尚未在 InnoDB 數據文件中的頁面組成,插入緩沖區主要用于處理索引的更改。
回滾段——這些段允許完成未提交事務的回滾操作。
撤消空間——這個空間包含告訴 MySQL 如何撤銷事務所做的最新更改的影響的記錄。
就MySQL而言,ibdata1獨占其旗艦存儲引擎——InnoDB(存儲引擎也是使用Percona XtraDB時的默認引擎。)InnoDB以其支持ACID事務的能力而廣為人知——ACID是一個非常重要的特性 即使在出現問題時也能保證數據的完整性和一致性——例如,如果我們正在運行一個查詢而我們的電力中斷了,我們的數據將不會受到影響。 然而,有一點需要注意——雖然我們可以隨時刪除存儲在 InnoDB 中的數據,但存儲在 ibdata1 中的數據不能。 雖然可以通過執行簡單的 DROP TABLE 命令(見下文)隨時刪除基于 InnoDB 的表,但 ibdata1 文件的大小只能在 my.cnf 文件中定義。
圖 1 - 使用 DbVisualizer 在數據庫中刪除一個表
詢問任何使用 MySQL 的經驗豐富的 DBA,您可以肯定他會建議您最好不要管 ibdata1,而是去做其他事情。 部分答案隱藏在 ibdata1 最初構建方式的核心背后——倒回并閱讀這一段之前的幾段——還記得我們是如何告訴你 ibdata1 存儲與 InnoDB 相關的所有數據的嗎?
ibdata1 的問題在于,當我們處理更大的數據集時,文件會變得大得不可思議——如果我們沒有將 innodb_file_per_table 選項設置為 1(這是從 MySQL 5.6.6 開始的默認選項), 它不能收縮。
如果我們沒有啟用 innodb_file_per_table 選項,或者如果我們運行的是舊版本的 MySQL,我們仍然可以采取一些措施來確保我們的 MySQL 實例即使在壓力下也能像蜜蜂一樣工作,方法是執行以下步驟:
我們需要備份 MySQL 基礎架構中的所有數據。
我們需要刪除 /var/lib/mysql/mysql*../data 文件夾下的所有數據庫(文件夾)(將 *..** 替換為您的 MySQL 版本)目錄,除了“mysql”和“performance_schema”文件夾 (它們是 MySQL 正常運行所必需的。)
我們需要確保 MySQL 已停止并刪除 ibdata1 和 ib_logfile0 & ib_logfile1 文件。 這些文件對 InnoDB 至關重要,因為它們都存儲了所有的重做日志,MySQL 在重新啟動后會讀取它們,但是如果適當的數據庫不在 MySQL 上次關閉時的完全相同的位置,MySQL 就會出現問題 啟動。
最后,我們需要整體重啟MySQL。
最后,我們需要重新導入我們在步驟 #1 中獲取的轉儲(始終應事先測試備份),如果我們返回數據文件夾,我們很可能會看到代表一個表的兩個文件(在此 例如,我們的表稱為 demo_table):
名為 demo_table.ibd 的文件存儲與表相關的所有數據。
名為 demo_table.frm 的文件存儲所有必要的雜項信息(與表相關的元數據)。
問題解決了——從現在開始,刪除基于 InnoDB 存儲引擎的表將是小菜一碟,即使我們無法通過 GUI 訪問 MySQL——刪除與表關聯的兩個文件就可以了,因為 從現在開始,ibdata1 將只存儲與運行 InnoDB 或 XtraDB 存儲引擎的表關聯的元數據,而不是數據本身。
圖 2 - DbVisualizer 中的表格及其相關文件
我們幾乎完成了——我們需要做的最后一件事是確保我們的 ibdata1 文件永遠不會太大以至于我們的系統無法處理。 我們可以通過完成以下步驟來做到這一點:
我們需要通過發出 df -h 命令找出磁盤上有多少空間。 此命令將以人類可讀的格式 (-h.) 為我們提供磁盤上的可用空間量 (df)
返回 my.cnf 并將設置 innodb-data-file-path 設置為在確定要在特定用例中分配給 MySQL 的磁盤空間量后適合您的值(參見下圖。)
重新啟動 MySQL 以使我們的更改生效。
圖 3 - my.cnf 中的 innodb-data-file-path 設置
在我們的示例中,ibdata1 的大小最初設置為 10GB,但它可以擴展(自動擴展)并且此文件的最大大小 (max) 不應超過 20GB。 由于在上一步中我們已確保該文件將僅存儲與表相關的元數據而不是數據本身,因此 20GB 的空間應該綽綽有余。
圖 4 – ibdata1 的初始大小
在本文中,我們帶您了解了整個 MySQL 基礎架構中最重要的文件——ibdata1。 我們已經教您如何確保此文件從長遠來看不會造成任何問題,并在此過程中演示了 DbVisualizer 的一些功能。 如果您喜歡閱讀本文,請關注我們的博客,找到與 DbVisualizer 和數據庫工程藝術相關的各種文章,以幫助釋放數據庫的力量并幫助您的公司取得成功,我們將在 下一個。
為了演示方便首先要造幾個鎖出來(下面的圖中分別使用了DbVisualizer,Sqldbx,命令行,所以截圖有點亂,您就將就著看吧)
1.查詢鎖信息
鎖的查詢有很多種方式,既可以寫SQL語句查詢,也可以在命令行里敲命令.對于大多數人來說SQL語句還是相對更直觀更簡單些.畢竟不是每個人都喜歡在命令行里敲,至少我是沒有習慣(水平比較差,沒辦法)
(1).使用SQL語句查詢:
方法1:
SELECT AGENT_ID, LOCK_OBJECT_TYPE, LOCK_MODE, LOCK_STATUS,TABNAME,TABSCHEMA FROM SYSIBMADM.SNAPLOCK;
方法2:
SELECT AGENT_ID, LOCK_OBJECT_TYPE, LOCK_MODE, LOCK_STATUS,TABNAME,TABSCHEMA FROM TABLE(SNAP_GET_LOCK('',-1));
以上兩個SQL語句雖然寫法稍有區別,但實際上返回結果是一樣的,主要看AGENT_ID, LOCK_MODE,TABNAME,TABSCHEMA 這幾列.
AGENT_ID:這個ID在下面需要用到
TABNAME:被鎖的表
TABSCHEMA:被鎖的表所在的SCHEMA
LOCK_MODE:鎖的類型,程序出問題,有時候鎖是什么類型并不是特別重要,導致程序出問題的并不一定是死鎖,本人是混醫療圈的,曾經有一次遇到一個很讓人郁悶的問題,程序的其中一個模塊登錄以后,什么活都沒干呢其他模塊就都跑不動了.當時以為有死鎖,可查詢結果只有幾個S鎖,翻代碼查數據庫抓SQL折騰好長時間發現程序登錄的時候有個多表關聯的查詢,其中一個數據量不算太小的表的索引出了問題,查詢特別慢,導致了其他模塊對表的訪問一直在后面排長隊等著。
(2).使用命令行查詢
在db2cmd里:db2 get snapshot for locks on sample(sample是數據庫名)
2.查詢鎖表的應用
在服務器的db2cmd里:db2 list application,列出當前連接數據庫的所有程序進程
下面抓取的結果顯示一共有4個進程連接SAMPLE數據庫,3個DB2系統進程,1個SQLDBX工具的進程
應用程序名:連接數據庫的應用程序的名字
應用程序句柄:這里的句柄就是上面查詢鎖里顯示的AGENT_ID
應用程序標識:這段里面顯示的是應用程序的客戶端IP地址等信息
數據庫名稱:這個就不用解釋了吧
根據1里查詢鎖的結果得到的AGENT_ID,在這里找到相應信息,找到鎖表的應用程序和IP地址,接下來那就該叫上網管一起干了,看看這個IP地址的那臺機器是誰在用,在做什么操作.如果在干壞事兒的話那必須得一頓暴打.
3.解鎖
好了,上面查也查了,打也打了.如果產生的是死鎖的話,即使關掉鎖表的客戶端應用,鎖也不會馬上釋放,接下來就需要手動解鎖了.
在服務器的db2cmd里:db2 force application(‘agentid’),其中小括號里的agentid就是上面所查詢到的應用程序句柄(AGENT_ID).其實這句話把小括號換成all也是可以的,db2 force application all,但是在生產環境上這句話可不能輕易使用,否則你就等著被暴打吧,因為這是要干掉所有的連接.