前言:學習mysql的時候總是習慣性的和oracle資料庫進行比較。在學習mysql InnoDB的儲存結構的時候也免不了跟oracle進行比較。Oracle的資料儲存有表空間、段、區、塊、資料檔案;mysql InnoDB的儲存管理也類似,但是mysql增加了一個共享表空間和獨立表空間的概念;
一、概念
共享表空間: Innodb的所有資料儲存在一個單獨的表空間裡面,而這個表空間可以由很多個檔案組成,一個表可以跨多個檔案存在,所以其大小限制不再是檔案大小的限制,而是其自身的限制。從Innodb的官方文件中可以看到,其表空間的最大限制為64TB,也就是說,Innodb的單表限制基本上也在64TB左右了,當然這個大小是包括這個表的所有索引等其他相關資料。
獨立表空間:
二、檢視資料庫的表空間
mysql> show variables like 'innodb_data%';
|
l 表空間有四個檔案組成:ibdata1、ibdata2、ibdata3、ibdata4,每個檔案的大小為10M,當每個檔案都滿了的時候,ibdata4會自動擴充套件;
l 當前的儲存空間滿的時候,可以在其他的磁碟新增資料檔案,語法如下:語法如下所示:
pathtodatafile:sizespecification;pathtodatafile:sizespec;.;pathtodatafile:sizespec[:autoextend[:max:sizespecification]]
如果用 autoextend 選項描述最後一個資料檔案,當 InnoDB 用盡所有表自由空間後將會自動擴充最後一個資料檔案,每次增量為 8 MB。示例:
不管是共享表空間和獨立表空間,都會存在innodb_data_file檔案,因為這些檔案不僅僅要存放資料,而且還要充當著類似於ORACLE的UNDO表空間等一些角色。
三、共享表空間優缺點
既然Innodb有共享表空間和獨立表空間兩種型別,那麼這兩種表空間存在肯定都有時候自己的應用的場景,存在即合理。以下是摘自mysql官方的一些介紹:
3.1 共享表空間的優點
表空間可以分成多個檔案存放到各個磁碟,所以表也就可以分成多個檔案存放在磁碟上,表的大小不受磁碟大小的限制(很多文件描述有點問題)。
資料和檔案放在一起方便管理。
3.2 共享表空間的缺點
所有的資料和索引存放到一個檔案,雖然可以把一個大檔案分成多個小檔案,但是多個表及索引在表空間中混合儲存,當資料量非常大的時候,表做了大量刪除操作後表空間中將會有大量的空隙,特別是對於統計分析,對於經常刪除操作的這類應用最不適合用共享表空間。
共享表空間分配後不能回縮:當出現臨時建索引或是建立一個臨時表的操作表空間擴大後,就是刪除相關的表也沒辦法回縮那部分空間了(可以理解為oracle的表空間10G,但是才使用10M,但是作業系統顯示mysql的表空間為10G),進行資料庫的冷備很慢;
四、獨立表空間的優缺點
4.1 獨立表空間的優點
每個表都有自已獨立的表空間,每個表的資料和索引都會存在自已的表空間中,可以實現單表在不同的資料庫中移動。
空間可以回收(除drop table操作處,表空不能自已回收)
Drop table操作自動回收表空間,如果對於統計分析或是日值表,刪除大量資料後可以透過:alter table TableName engine=innodb;回縮不用的空間。
對於使innodb-plugin的Innodb使用turncate table也會使空間收縮。
對於使用獨立表空間的表,不管怎麼刪除,表空間的碎片不會太嚴重的影響效能,而且還有機會處理。
4.2 獨立表空間的缺點
單表增加過大,當單表佔用空間過大時,儲存空間不足,只能從作業系統層面思考解決方法;
五、共享表空間和獨立表空間之間的轉換
5.1 檢視當前資料庫的表空間管理型別
指令碼:show variables like "innodb_file_per_table";
mysql> show variables like "innodb_file_per_table";
|
ON代表獨立表空間管理,OFF代表共享表空間管理;(檢視單表的表空間管理方式,需要檢視每個表是否有單獨的資料檔案)
5.2 修改資料庫的表空間管理方式
修改innodb_file_per_table的引數值即可,但是修改不能影響之前已經使用過的共享表空間和獨立表空間;
innodb_file_per_table=1 為使用獨佔表空間
innodb_file_per_table=0 為使用共享表空間
5.3共享表空間轉化為獨立表空間的方法(引數innodb_file_per_table=1需要設定)
單個表的轉換操作,指令碼:alter table table_name engine=innodb;
當有大量的表需要操作的時候,先把資料庫匯出,然後刪除資料再進行匯入操作,該操作可以用mysqldump進行操作(http://blog.itpub.net/12679300/viewspace-1259451/)
總結:經過以上操作便完成資料庫的儲存空間的轉換,瞭解技術是為了更好的利用技術,當資料量很小的時候建議使用共享表空間的管理方式。資料量很大的時候建議使用獨立表空間的管理方式。
Advantages of File-Per-Table Mode
1 當truncate或者drop一個表時可以釋放磁碟空間。如果不是獨立表空間,truncate或drop一個表只是在ibdata檔案內部釋放,實際ibdata檔案並不會縮小,釋放出來的空間也只能讓其他innodb引擎的表使用(有時這會造成磁碟空間容量監控的一個痛點,無法判斷它到底有多滿)
2 獨立表空間下,truncate table操作會更快
3 獨立表空間下,可以自定義表的儲存位置,透過CREATE TABLE ... DATA DIRECTORY =absolute_path_to_directory命令實現(有時將部分熱表放在不同的磁碟可有效地提升IO效能)
4 獨立表空間下,可以回收表空間碎片(比如一個非常大的delete操作之後釋放的空間),alter table xxx engine=innodb
5 可以移動單獨的innodb表,而不是整個database
6 可以copy單獨的innodb表從一個例項到另外一個例項(也就是transportable tablespace特色)
7 獨立表空間模式下,可以使用Barracuda的檔案格式,這個檔案格式有壓縮和動態行模式的特色。這個當表中有blob或者text欄位的話,動態行模式(dynamic row format)可以發揮出更高效的儲存。
8 獨立表空間模式下,可以更好的改善故障恢復,比如更加節約時間或者增加崩潰後正常恢復的機率。
9 單獨備份和恢復某張表的話會更快
10 可以使得從一個備份中單獨分離出表,比如一個lvm的快照備份
11 可以在不訪問的情況下方便地得知一個表的大小,即在檔案系統的角度上檢視。
12 在大部分的linux檔案系統中,如果innodb_flush_method為O_DIRECT,通常是不允許針對同一個檔案做併發寫操作的。這時如果為獨立表空間模式的話,應該會有較大的效能提升。
13 如果沒有獨立表空間模式,那麼所有的東西都在共享表空間,而共享表空間是有64T的容量上限的(這點比較扯淡)
Potential Disadvantages of File-Per-Table Mode
1 獨立表空間模式下,每個表或許會有很多沒用到的磁碟空間,因為初始表空間大小是固定的吧,有些表根本沒使用都這麼多。如果沒做好管理,可能會造成較大的空間浪費。
2 fsync操作必須執行在每一個單一的檔案上,獨立表空間模式下,多個表的寫操作就無法合併為一個單一的IO,這樣就新增許多額外的fsync操作
3 mysqld必須保證每個表都有一個open file,獨立表空間模式下,這樣就需要很多開啟檔案數,可能會影響效能
4 當drop一個表空間時,buffer pool會被掃描,如果buffer pool有幾十G那麼大,或許要花費幾秒鐘時間。這個掃描操作還會產生一個內部鎖,可能會延遲其他操作,共享表空間模式下不會有這個問題。
5 如果許多表都增長迅速,那麼可能會產生更多的分裂操作(應該指的是表空間大小的擴充),這個操作會損害drop table和table scan的效能。
6 innodb_autoextend_increment引數對獨立表空間無效,這個引數指的是當系統表空間滿了以後,它再次預先申請的磁碟空間大小,單位為M
Copying Tablespaces to Another Server(Transportable Tablespaces)
Transportable Tablespaces特性可以處理以下幾個痛點
1 跑報表,單獨拎出需要的幾個表到新的例項上跑報表,可以保證報表產生巨大伺服器開銷不影響到現網服務
2 透過這個特性快速地建立一個新的slave
3 在當前庫發生一個故障後備份一個該表的臨時版本
4 一種比mysqldump更快的moving data的方式
5 可以將部分表移交到一個更合適的硬體環境下,比如小而操作頻繁的放在SSD下,大而操作不頻繁的放在HDD
Tablespace Copying Limitations and Usage Notes(Transportable Tablespaces)
1 必須是在獨立表空間模式下
2 在遷移過程中,涉及到的表只讀不可寫
3 兩邊的page size必須保持一致(innodb_page_size)
4 DISCARD TABLESPACE操作不一致分割槽表,否則報錯ERROR 1031 (HY000): Table storage engine for 'part' doesn'thave this option.
5 DISCARD TABLESPACE時,如果foreign_key_checks為1,那麼不支援存在外來鍵約束的表
6 ALTER TABLE ... IMPORT TABLESPACE操作不會去檢查外來鍵約束
7 ALTER TABLE ... IMPORT TABLESPACE並不需要.cfg的後設資料檔案來匯入一個表空間。但是,這樣的話就沒有後設資料檢查了,同時會給出一個waring
Message: InnoDB: IO Read error: (2, No suchfile or directory) Error opening '.\
test\t.cfg', will attempt to import without schema verification
1 row in set (0.00 sec)
如果確認schema沒有配錯,那麼不用.cfg檔案可能更方便簡潔,並且有利於後設資料無法在.ibd檔案裡收集的故障恢復。
8 主從環境下,master和slave都必須設定為獨立表空間模式
Example Procedure: Copying a Tablespace From One Server ToAnother (Transportable Tablespaces)
1 在源server上,建立一個測試表
mysql> use test;
mysql> CREATE TABLE t(c1 INT) engine=InnoDB;
2 在目標server上,同樣建立出相同表結構的表
mysql> use test;
mysql> CREATE TABLE t(c1 INT) engine=InnoDB;
3 在目標server上,discard掉該表的表空間
mysql> ALTER TABLE t DISCARD TABLESPACE;
4 在源server上,執行FLUSH TABLES ... FOR EXPORT命令來靜默這張表,並建立出.cfg後設資料檔案(.cfg檔案建立在innodb的data目錄)
mysql> use test;
mysql> FLUSH TABLES t FOR EXPORT;
5 複製源server上的.ibd和.cfg檔案到目標server上
shell> scp /path/to/datadir/test/t.{ibd,cfg}destination-server:/path/to/datadir/test
6 在源server上,使用unlock tables命令來釋放flush tables..for export命令上的鎖
mysql> use test;
mysql> UNLOCK TABLES;
7 在目標server上,匯入表空間
mysql> use test;
mysql> ALTER TABLE t IMPORT TABLESPACE;
Tablespace Copying Internals (Transportable Tablespaces)
ALTER TABLE ... DISCARD TABLESPACE做了下面這兩件事
1 給table加X鎖
2 分離出表空間
FLUSH TABLES ... FOR EXPORT做了以下幾件事
1 給table加S鎖
2 停止purge執行緒
3 髒頁重新整理到磁碟
4 表的後設資料寫到.cfg檔案
Unlock tables做了以下幾件事
1 刪除.cfg檔案
2 釋放之前的共享鎖,並重啟purge執行緒
ALTER TABLE ... IMPORT TABLESPACE做了以下幾件事
1 檢查表空間內的每個頁是否有損壞
2 更新每頁上的space ID和LSNs
3 更新開頭頁的有效標誌位和LSN
4 更新btree頁
5 將頁狀態改為“髒頁”,重新整理到磁碟
Storing InnoDB Undo Logs in SeparateTablespaces
5.6.3以前,innodb undo log存放在系統表空間,5.6.3以後可將undo log從系統表空間中分離出來。這樣帶來的好處是,可將undo放到SSD盤提升效能。這個特性主要由這幾個引數實現
innodb_undo_tablespaces:undo logs建立的表空間檔案數量,預設為0,表示存放在系統表空間,最大值為126
innodb_undo_directory:undo logs存放的路徑,預設為.表示和其他日誌檔案一致
innodb_undo_logs:系統表空間中在一個事務裡最大使用到的回滾段數量,預設為最大值128
分離步驟如下
1 決定undo logs的存放路徑,修改innodb_undo_directory引數
2 決定一個非0的innodb_undo_logs值,可以透過壓測決定到底取啥值,起始值設定小一些
3 決定一個非0的innodb_undo_tablespaces值
4 利用上述配置建立出新的mysql例項
5 壓測IO負載情況
6 壓測期間慢慢增大innodb_undo_logs,找到最合適的值
7 上生產環境下再測試觀察
Changing the Number or Size of InnoDB LogFiles and Resizing the InnoDB Tablespace
Changing the Number or Size of InnoDB Log Files
1 SET GLOBAL innodb_fast_shutdown = 1;
2 正常關閉mysqld程式,確保正常關閉
3 備份舊的log files
4 刪除舊的log files
5 修改my.cnf配置
6 重啟mysqld,確保啟動後log files的數量和新配置一致
5.6.8以後的版本,不再需要innodb_fast_shutdown,也不用刪除舊的log files。
Increasing the Size of the InnoDB Tablespace
由innodb_data_file_path引數的autoextend引數控制就好,表空間會自動增長。預設每次增長為8M,系統表空間每次增長量可由引數innodb_autoextend_increment控制。如果要兩個系統表空間檔案,一個固定大小,一個自增,可以這麼弄(建議一個就好,不要這麼搞,有點亂,不好管理)
innodb_data_file_path =/ibdata/ibdata1:988M;/disk2/ibdata2:50M:autoextend
Decreasing the Size of the InnoDB Tablespace
獨立表空間回收磁碟空間,只要執行alter table xx engine=innodb就行,系統表空間回收步驟如下
1 使用mysqldump dump出所有的表
2 關閉mysql
3 刪除整個data目錄,包括ibdata檔案和log file
4 啟動mysql
5 匯入dump檔案
要說表空間,Mysql的表空間管理遠遠說不上完善。換句話說,事實上Mysql根本沒有真正意義上的表空間管理。Mysql的Innodb包含兩種表空間檔案模式,預設的共享表空間和每個表分離的獨立表空間。只要在my.cnf裡面增加innodb_file_per_table=1就可以從共享表空間切換到獨立表空間。當然對於已經存在的表,則需要執行alter table MY_TABLE engine=innodb命令遷移資料。
共享表空間方式
由於是預設的方式,就暫且理解為Mysql官方推薦的方式。相對而言所有的資料都在一個(或幾個)檔案中,比較利於管理,而且在操作的時候只需要open這一個(或幾個)檔案即可,相對來說代價很低。
但問題是在資料達到以G為單位來計算的時候優劣逆轉。一個大小驚人的檔案很不利於管理,而且對於一個如此巨大的檔案來說,讀寫它需要耗費的資源一樣巨大。更加令人費解的是,MySQL竟然將索引和資料儲存於同一個檔案中,索引和資料之間尚存在資源爭用,不利於效能的提升。你當然可以透過innodb_data_file_path的配置規劃多個表空間檔案,但MySQL的邏輯是“用滿後增加”,僅僅是一個檔案的拆分而已,不能從根本上分離資料和索引。
之前曾經遭遇到700G以上的表空間檔案,而且更加讓人鬱悶的是對於如此大的檔案還在以每天數G的數量增加。由於無法停機,即便是複製一下也要花費差不多一夜,只能眼睜睜看著它繼續增大而毫無保守可行的辦法。
獨立表空間方式
相對而言對立表空間每個表都有獨立的多個資料檔案,而且做到了索引和資料的分離。多個小檔案之間很方便的完成跨資料庫甚至跨硬體的資料複製和遷移。相對來說靈活性很好。
這樣做同樣帶來另一個方面的問題。當資料庫中的表數量達到一定級別時,每次操作所涉及的檔案過多,如果按照預設Centos的ulimit -n = 1024的話,僅僅只能保證同時開啟256個表以內,這在習慣上“拆庫拆表”的MySQL資料結構上很難達到要求。尚且這種資料檔案的利用率不算很高,當大量“不高”的檔案集中起來,浪費的空間也很驚人,更何況最後可能出現的狀況不是“一堆K級別的小檔案”而是“一堆G級別的大檔案”,有點適得其反的意思。你自然可以聯想到分割槽表,又是一個“僅僅做檔案拆分而已”,多個分割槽檔案缺一不可。
之前同樣遇到過這個問題,MySQL連線大的狀況下大量的timeout,但主機負載還算可以,查了一圈才知道是open files限制的問題,限制一修改,負載變得驚人,但連線數卻又提升的不多。
總之,兩種方法各有所長,部分互補,但都不是解決問題的終極方案。期待MySQL能夠出現真正意義上表空間的概念,更加自由的規劃資料檔案。