爲不瞭解存儲引擎的數據庫使用者,提供了很大的便利,由於innodb適應大部分應用場景。mysql
和myisam不一樣的是,innodb是一種事務型存儲引擎。也就是說,innodb是支持事務的acid特性的。innodb的設計,更適合大量的小事務,而小事務大部分狀況下, 均可以正常提交,不多會被回滾。git
innodb和mysiam存儲數據方式不一樣,innodb有本身的表空間的概念。表中的數據是存儲在表空間之中的,具體存儲在什麼樣的表空間中了,則由 innodb_file_per_table
這個參數來決定。github
ON: 爲每一個innodb表創建一個空間,tablename.ibd(.ibd後綴)
sql
OFF:則會把數據存儲到系統的共享表空間,ibdatax(x表明一個數字,從1開始)
數據庫
在mysql5.6以前的innodb參數-innodb_file_per_table = OFF (默認),也就是數據默認會存儲到系統表空間中。緩存
默認的設置會遇到下面的問題:在一個繁忙的系統中,系統表空間不斷的增加。沒超過咱們磁盤限制是能夠接受的,可是一旦咱們磁盤空間出現不足,咱們爲了釋放磁盤空間,不得不在系統中刪除大量無效的數據(如:長期不使用的日誌類數據等)。咱們在刪除數據後,系統表空間並不會縮小。這種狀況下,咱們想經過複製文件的方式,對數據庫進行備份。因爲雖然刪除了數據,但表空間大小並不會改變,這就意味着,咱們每次刪除時,都要浪費很大的空間。安全
你不要覺得咱們不會遇到備份的問題,實際上,目前咱們最經常使用的熱備方式,就是這樣處理的。這時咱們就會遇到使用系統表空間進行存儲的一些問題了。服務器
想要收縮系統表空間的惟一方法就是把系統表空間的表導出後,刪除innodb的文件後,在重啓mysql服務器,進行表空間的重建,而後在導入數據。這個過程實際上是很複雜的,而且十分耗時,這在業務繁忙的生產環境中了,顯然是不可能作到的。架構
因此咱們若是使用系統表空間進行表數據的存儲,所面臨的問題是沒法很容易的收縮系統文件,形成大量的空間浪費,而且會產生大量的磁盤碎片,從而下降了系統性能。併發
若是咱們使用獨立表空間, 對一個大表的數據進行清理以後,能夠方便的對這個表進行收縮,使用optimize table
命令 ,會對錶進行重建。可是對比整個系統進行重建要快的多,並且不須要重啓數據庫服務器,甚至不會影響這個表的正常訪問。因此從這點來看,使用獨立的表空間顯然要比使用系統表空間要好得多。
對於系統個表空來講,因爲只有一個文件。若是同時對多個表進行數據刷新時,實際上在文件系統層面上來講是順序進行的,因此會產生必定的io瓶勁。
對於獨立表空間來講,因爲每一個表都有本身的表空間文件。在進行數據寫入時,能夠利用多個文件增長io處理的性能。因此對於平凡寫入操做的系統來講,不太適合使用系統表空間統一存放數據,而是要使用獨立表空間的方式。
對使用innodb存儲引擎的表使用獨立表空間進行管理,在mysql5.6後,使用innodb存儲引擎的默認表配置就是獨立存儲空間。
把原來存在於系統表空間中的錶轉移到獨立表空間中的方法
若是數據庫中使用存儲過程,觸發器,計劃事件等,必定要記得一塊兒導出。
中止mysql服務,若是是主從架構的話,咱們能夠先從-從服務器上進行這些操做。中止mysql服務器以後,咱們須要修改my.cnf文件,並加入innodb_file_per_table
這個參數,而後手動刪除原來innodb系統中的相關數據文件,這時後系統表空間就不含有任何數據了。
實際上,因爲咱們以前已經備份了全部數據表,因此這裏能夠重建一個data目錄,並使用mysql install db腳原本重建數據庫目錄
從新導入以前備份的數據,就能夠完成數據的恢復,而且把原來存在於系統表空間的數據遷移到獨立表空間中了。
咱們也可不按照上面操做,在修改完系統參數後,重啓服務後將須要修改的全部innodb表都執行一遍:alter table table_name engine=innodb;
.這樣也能夠把系統表空間的表遷移到獨立表空間中,可是卻沒法對系統表空間所佔用的空間進行回收,因此仍是按照上面正規步驟吧。
咱們把系統表空間數據遷移到獨立表空間後,那麼如今系統表空間還有什麼內容了?
答案是雖然咱們已經把系統表數據遷移了出來,可是對於系統表空間來講,仍是有一些很重要的東西要存儲的。這其中之一就是 innodb數據字典信息
數據字典是數據對象結構的元數據信息,存放與數據庫對象相關的信息。如:表,列,索引,內鍵等內容
。
mysql是使用 .frm文件存儲表結構定義的,那麼.frm文件和系統空間中的數據字典又有什麼區別了?
首先,.frm文件是mysql服務器層產生的文件,能夠理解爲mysql數據庫服務器層的數據字典,這對mysql全部存儲引擎都是同樣的。mysql數據層所保留的東西是與存儲引擎無關的,而innodb內部的數據字典是存儲引擎內部產生的,並能夠保證事務的一些安全性。另外,innodb存儲引擎沒有直接使用mysql數據上的一些類型,而是本身封裝了定義,所以其數據字典存儲的都是引擎相關的內容。最後,.frm文件只是簡單的二進制文件,而innodb數據字典是經過b樹
來進行數據管理的
除了innodb數據字典外,系統表空間還存在undo回滾段和innodb臨時表
這兩種在mysql5.7都是能夠從系統表移除的 了,但還會有不少人默認的把他們存儲在系統表空間中。這裏要聲明的是,undo回滾段的存儲在mysql5.6就已經支持了。
徹底支持事物的acid特性
redo log 和 undo log
redo log實現事物的持久性,其有兩部分組成
innodb_log_buffer_size:配置redo log緩衝區的大小,以字節爲單位,程序每隔秒就會把緩存區數據刷新到磁盤裏,因此這個緩存區不用配置太大。
innodb_log_files_in_group:決定了數據庫目錄下的ib_**的文件數量
undo log 幫助對未提交事物進行回滾和實現多版本併發控制
聯繫
同myisam支持的表級鎖是不同的,行級鎖的特色是在進行寫操做時,咱們所須要鎖定的資源更少,這樣能夠支持的併發就更多。須要注意的是,innodb的行級鎖是由存儲引擎層實現的,mysql服務器徹底不瞭解存儲引擎中鎖的實現方式。
說到鎖可能你們還不太瞭解,數據庫中鎖的做用是什麼了?由於鎖對咱們數據庫的性能有很是大的影響,因此這裏介紹下什麼是鎖。
可能不少開發人員會問,常常聽到dba說的各類各樣的鎖,好比說行級鎖,表級鎖,共享鎖,專斷鎖等等。這些鎖的做用是啥了?
鎖是數據庫系統區別於文件系統的重要特性鎖的主要做用是管理共享資源的併發訪問
。併發訪問是一個很讓人頭疼的事情啊,對於任何一個在竄行環境下工做良好的系統,一旦涉及到併發的狀況就有可能出現各類各樣的問題。
好比說郵件系統,在一個郵箱中,全部的郵件都是竄行的疊在一塊兒的,彼此首尾相連。這種結構對於讀取和投遞郵件都是有很大的好處的。當有新的郵件到來時,只要插入文件末尾就能夠了。當有兩個用戶,同時對郵箱進行郵件投遞,那會出現什麼樣的狀況了?頗有可能郵箱的數據會被破壞,兩封性的內容會交叉在一塊兒。固然了,這可能和咱們日常生活的感覺有很大的不一樣。那是由於如今的郵箱系統都是利用了鎖進行了控制。鎖保證了一個用戶向郵箱投遞郵件時,另外一個用戶會阻塞,沒法向相同的文件末尾寫入文件。
那麼鎖的另外一個做用就是實現事務的隔離性
。前面提到過,咱們經過redo log 和 undo log 實現了事務的原子性,一致性和持久性,而隔離性就須要鎖來實現。對於未提交的事務鎖定的數據是沒法被其餘事務查詢到的。
瞭解了什麼是鎖,及鎖的做用後,咱們來看看鎖的常見分類。
共享鎖(也稱讀鎖):能夠看出讀鎖是共享的,不會被阻塞的, 多個線程能夠在同一時間讀取同一資源,而不相互干擾。
獨佔鎖(也稱寫鎖):寫鎖是獨佔的,是排它的,會阻塞其餘的寫鎖和讀鎖。這是對數據完整性的考慮,只有這樣才能保證在給定的時間裏,只有一個線程能夠執行寫入,並防止其餘用戶正在讀取寫入的資源,也就是咱們前面說的事務的隔離性。
對於innodb來講,讀鎖和寫鎖都是行鎖。兼容性指的是對同一行記錄可見兼容的狀況
按照上面介紹,對於同一資源的請求應該是互斥的,可是實際體驗並不和以上相同。(鎖比上面提到的複雜多了)
初始化數據庫中數據
測試,兩個鏈接啓動一個事務。一個鏈接給表的第一行記錄加個獨佔鎖,不提交事務
另外一個鏈接獲取加了獨佔鎖的數據,仍然能夠獲取到
這和咱們介紹的兼容性狀況徹底不一樣,這是爲何了?
這就是innodb在實現鎖上的獨到之處,這裏innodb用到了咱們上面提到的undo log中的記錄,因此咱們在第二個鏈接中查看的數據其實是存儲在undo log中的版本。也就是說,並非咱們在第一個鏈接中進行更新的。
鎖的粒度就是鎖的策略,指被加鎖資源的最小單位
。好比在行上加鎖,那麼最小單位就是行,這鎖就稱爲行級鎖。若是說的最小單位是列,那就稱爲鎖的列級鎖。同理,若是鎖的最小單位是表的話,那麼鎖的最小單位就是表級鎖。
表級鎖:mysql中最基本的表策略,開銷最小的策略,併發性低。表鎖會在加鎖時鎖定整張表,一個用戶在對錶進行寫操做前,須要先得到寫鎖。這會阻塞其餘用戶的讀寫操做,只有沒有寫鎖時,其餘用戶才能夠獲取讀鎖,讀鎖以前說了是相互間不會阻塞的。表級鎖一般是在mysql服務器層實現的,因此雖然innodb實現了行級鎖,可是在一些時候,mysql數據服務層仍是會對innodb表加上表級鎖。
實驗使用兩個鏈接,一個鏈接加表級獨佔鎖
第二個鏈接從表獲取數據
第一個鏈接執行解鎖操做,第二個鏈接就會被執行
行級鎖:能夠最大程度的支持併發處理,同時鎖的開銷比表級鎖要大。目前innodb和其餘的存儲引擎中實現了行級鎖,行級鎖只在存儲引擎中進行實現,而mysql服務層並無實現。
什麼是阻塞:阻塞是不一樣鎖之間兼容性的關係。在有些時刻,一個事務中的鎖須要等待另外一事務中的鎖釋放它所佔用的資源,這就造成了阻塞。阻塞是爲了確保事務能夠併發且正常的運行, 可是,當一個系統中若是出現了大量的阻塞,每每就意味着系統中存在着問題。也許是在一個被頻繁更新的表上出現了慢查詢或是因爲其餘的管理操做,如表備份等。對一個頻繁訪問的資源加上了排他鎖,過多的阻塞不是個好的現象,使數據庫中的鏈接大量的堆積,佔用大量的系統資源,使得系統的整體性能降低。
什麼是死鎖:死鎖是指兩個或兩個以上的事務,在執行過程當中相互佔用了對方等待的資源 ,而產生的一種異常。處在阻塞中的事務佔有被阻塞事務的多個資源,而死鎖是產生事務的多個事務之間相互佔用對方等待的資源,這就是阻塞和死鎖最大的不一樣之處。另一點不一樣是,死鎖數據庫系統會自動發現,而且在多個資源佔用的事務中,選擇一個資源佔用最少的事務來進行回滾操做。這樣就可使其餘事務正常的運行了,因此說死鎖是能夠由系統自動處理的。若是隻是有少許的死鎖,並不會對系統形成什麼影響。只要在應用程序中,發現死鎖,並進行從新處理就能夠了。可是,若是一個系統中頻繁的出現大量的死鎖,這時就須要留意了。一般狀況下,死鎖能夠經過在多個事務中按相同的順序訪問所須要的資源來解決,也可經過增長相關的索引來解決。
show engine innodb status 這命令的用法百度
innodb適合於大多數OLTP應用。不管是否須要事務支持,只要是不使用innodb所不支持的特殊的功能的話,咱們都應該在新的系統中使用innodb存儲引擎。其中所說的特殊功能可能就包括以前介紹myisam功能中對於空間應用和全文索引這些應用。因爲在mysql5.7以前,只支持myisam存儲引擎,因此若是咱們要使用mysql來存儲這類應用數據的話,可能就只能選擇myisam存儲引擎了。但是這種狀況在mysql5.7以後有了改變,innodb支持全文索引和空間函數了
。 因此對於這類應用,咱們也能夠徹底使用innodb存儲引擎來進行存儲了。innodb和myisam是mysql最經常使用的兩種存儲引擎,還有一些引擎會使用到,請聽下回分解。
InnoDB 引擎獨立表空間 innodb_file_per_table
MySQL Server參數優化 - innodb_file_per_table(獨立表空間)
show engine innodb status解讀
死鎖和阻塞的關係