日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL之架构与历史(二)

發布時間:2024/4/17 数据库 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL之架构与历史(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

多版本并發控制

MySQL的大多數事務型存儲引擎實現的都不是簡單的行級鎖。基于提升并發性能的考慮,它們一般都同時實現了多版本并發控制(MVCC)。不僅是MySQL,包括Oracle、PostgreSQL等其他數據庫系統也都實現了MVCC,但各自的實現機制不盡相同,因為MVCC沒有一個統一的實習標準。

可以認為MVCC是行級鎖的一個變種,但是它在很多情況下避免了加鎖操作,因此開銷更低。雖然實現機制不同,但大都實現了非阻塞的讀操作,寫操作也只鎖定了必要的行。

MVCC的實現,是通過保存數據在某個時間點的快照來實現的。也就是說,不管需要執行多長時間,每個事務看到的數據都是一致的。根據事務開始的時間不同,每個事務對同一張表,同一時刻看到的數據可能是不一樣的。

前面說到不同存儲引擎的MVCC實現是不同的,典型的有樂觀(optimistic)并發控制和悲觀(pessimistic)并發控制。下面我們通過InnoDB的簡化版行為來說明MVCC是如何工作的。

InnoDB的MVVC,是通過在每行記錄后面保存兩個隱藏列來實現的。一個保存了行的創建時間,一個保存了行的過期時間(或刪除時間)。當然存儲的并不是實際的時間值,而是系統版本號(system version number)。每開啟一個新的事務,系統版本號都會自動遞增。事務開始時刻的系統版本號會作為當前事務的版本號,用來和查詢到的每行記錄的版本號進行比較。下面看一下在REPEATABLE READ 隔離級別下,MVCC具體是如何操作的。

SELECT

InnoDB會根據一下兩個條件檢查每行記錄:

  • InnoDB只查找版本早于當前事務版本的數據行(也就是,行的系統版本號小于等于當前事務的系統版本號),這樣可以確保事務讀取的行,要么實在事務開始前就已經存在的,要么是事務自身插入或修改過的。
  • 行的刪除版本要么未定義,要么大于當前事務版本號。這可以確保事務讀取到的行,在事務開始之前未被刪除。

只有符合上述兩個條件的記錄,才能作為返回結果。

INSERT

InnoDB為新插入的每一行保存當前的系統版本號作為行版本號。

DELETE

InnoDB為刪除的每一行保存當前系統版本號作為行刪除標識。只有commit的時候才會真正刪除。

UPDATE

InnoDB為插入一行新記錄,保存當前系統版本號作為行版本號,同時保存當前系統版本號到原來的行作為行刪除標識。


保存這兩個額外系統版本號,使大多數讀操作都可以不用加鎖。這樣設計使得讀數據操作很簡單,性能很好,并且也能保證只會讀取到符合標準的行。不足之處是每行記錄都需要額外的存儲空間,需要做更多的行檢查工作,以及一些額外的維護工作。

MVCC只在REPEATABLE READ和READ COMMITTED 兩個隔離級別下工作。其他兩個隔離級別都和MVCC不兼容 ,因為READ UNCOMMITTED 總是讀取最新的數據行,而不是符合當前事務版本的數據行。而SERIALIZABLE 則會對所有讀取的行都加鎖。

MySQL的存儲引擎

在文件系統中,MySQL將每個數據庫(也稱為schema)保存為數據目錄下的一個子目錄。創建表時,MySQL會在數據庫子目錄下創建一個和表同名的.frm文件保存表的定義。因為MySQL使用文件系統的目錄和文件來保存數據庫和表的定義,大小寫敏感和具體的平臺密切相關。在Windows中,大小寫是不敏感的;而在類Unix中則是敏感的。不同的存儲引擎保存的數據和索引的方式是不同的,但表的定義則是在MySQL服務層統一處理的。

可以使用SHOW TABLE STATUS命令查看表的相關信息。例如,對于mysql數據庫中的user表:

mysql> use mysql; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -ADatabase changed mysql> SHOW TABLE STATUS LIKE 'user'\G; *************************** 1. row ***************************Name: userEngine: InnoDBVersion: 10Row_format: DynamicRows: 5Avg_row_length: 3276Data_length: 16384 Max_data_length: 0Index_length: 0Data_free: 4194304Auto_increment: NULLCreate_time: 2018-10-05 22:37:53Update_time: NULLCheck_time: NULLCollation: utf8_binChecksum: NULLCreate_options: stats_persistent=0Comment: Users and global privileges 1 row in set (0.04 sec)

  

  • Name:表名。
  • Engine:表的存儲引擎。在舊版本中,該列的名字叫Type,而不是Engine。
  • Version:版本。
  • Row_format:行格式。對于MyISAM引擎,這可能是Dynamic,Fixed或Compressed。Dynamic(動態行)的行長度可變,一般包含可變長的字段,如Varchar或Blob 類型字段。Fixed(固定行)是指行長度是不變的,只包含固定的長度列,例如Char和Integer類型字段。Compressed的行旨在壓縮表中存在。
  • Rows:表中的行數。對于非事務性表(MyISAM),這個值是精確的,對于事務性引擎(InnoDB),這個值通常是估算的。
  • Avg_row_length:平均每行包含的字節數(單位:字節)
  • Data_length:整個表的數據量(單位:字節)
  • Max_data_length:表可以容納的最大數據量,該值和存儲引擎有關。
  • Index_length:索引占用磁盤的空間大小(單位:字節)
  • Data_free:對于MyISAM表,表示已分配,但現在未使用的空間,并且包含了已被刪除行的空間(行),以及后續可以被INSERT利用到的空間。
  • Auto_increment:下一個Auto_increment的值
  • Create_time:表的創建時間。
  • Update_time:表的最近修改時間(更新時間)。
  • Check_time:使用check table命令或myisamchk工具最近一次檢查表時間。
  • Collation:表的默認字符集和字符排序規則。
  • Checksum:如果啟用,保存的是整個表的實時校驗和。
  • Create_options:指表創建時的其他所有選項。
  • Comment:包含了其他額外信息,MyISAM引擎(表),保存的是表在創建時已有的注釋;innodb引擎(表),保存的是InnoDB表空間的剩余空間信息;如果是一個視圖,該列(注釋)里面包含了"VIEW"字樣。

InnoDB存儲引擎

InnoDB是MySQL的默認事務型引擎,也是最重要、使用最廣泛的存儲引擎。他被設計出來處理大量的短期事務,短期事務大部分情況是正常提交的,很少會被回滾。InnoDB的性能和自動崩潰恢復特性,使得他在非事務型存儲需求中也很流行。除非要特別重要的原因需要使用其他存儲引擎,否則應該優先考慮InnoDB。

InnoDB概覽

InnoDB的數據存儲在表空間中,表空間是由InnoDB管理的一個黑盒子,由一系列的數據文件組成。。在MySQL4.1以后的版本中,InnoDB可以將每個表的數據和索引存放在單獨的文件中。InnoDB也可以使用裸設備作為表空間的存儲介質,但現代的文件系統使得裸設備不再是必要選擇。

InnoDB采用MVCC來支持高并發,并且實現了四個標準的隔離級別。其默認級別是REPEATABLE READ(可重復讀),并且通過間隙鎖策略防止幻讀的出現。間隙鎖使得InnoDB不僅僅鎖定查詢涉及的行,還會對索引中的間隙進行鎖定,以防止幻影行的插入。

InnoDB表是基于聚簇索引建立的,InnoDB的索引結構和MySQL的其他存儲引擎有很大不同,聚簇索引對主鍵查詢有很高的性能。不過它的二級索引(非主鍵索引)中必須包含主鍵列,所以如果主鍵列很大的話,其他的索引都會很大。因此,若表上的索引較多的話,主鍵應當盡可能的小。

InnoDB內部做了很多優化,包括從磁盤讀取數據時采用的可預測性預讀,能夠自動在內存中創建hash索引以加速讀操作的自適應哈希索引(adaptive hash index),以及能夠加速插入操作的插入緩沖區(insert buffer)等。

MyISAM存儲引擎

在MySQL 5.1及之前的版本,MyISAM是默認的存儲引擎。MyISAM提供了大量的特性,包括全文索引,壓縮,空間函數(GIS)等,但MyISAM不支持事務和行級鎖且有一個毫無疑問的缺陷就是崩潰后無法安全恢復。正是由于MyISAM引擎的緣故,即使MySQL支持事務已經很長時間了,在很多人的概念中MySQL還是非事務性的數據庫。盡管MyISAM引擎不支持事務,不支持崩潰后的安全回復,但它絕不是一無是處的。對于只讀的數據,或者表比較小,可以忍受修復操作,則依然可以繼續使用MyISAM。

存儲

MyISAM會將表存儲在兩個文件中:數據文件和索引文件,分別以.myd和.myi為拓展名。MyISAM表可以包含動態或者靜態(長度固定)行。MySQL會根據表的定義來決定采用何種行格式。MyISAM表可以存儲的行記錄數,一般受限于可用磁盤控件,或者操作系統中單個文件的最大尺寸。

MyISAM特性

加鎖與并發:MyISAM對整張表進行加鎖,而不是針對行。讀取時會對需要讀到的所有表加共享鎖,寫入時則對表加排他鎖。但是在表有讀取查詢的時候,也可以往表中插入新的記錄(這被稱為并發插入)。

修復:對與MyISAM表,MySQL可以手工或者自動執行檢查和修復操作,但這里說的修復和事務回復以及崩潰恢復是不同的概念。執行表的修復可能導致一些數據丟失,而且修復操作是非常慢的。可以通過CHECK TABLE mytable檢查表的錯誤,如果有錯誤可以通過執行REPAIR TABLE mytable進行修復。另外,如果MySQL服務器已經關閉,可以通過myisamchk命令行工具進行檢查和修復操作。

索引特性:對于MyISAM表,即使是BLOB和TEXT等長字段,也可以基于其前500個字符創建索引,MyISAM也支持全文索引,這是一種基于分詞創建的索引,可以支持復雜的查詢。

延遲更新索引:創建MyISAM表的時候,如果指定了DELAY_KEY_WRITE選項,在每次修改執行完成時,不會立刻將修改的索引數據寫入磁盤,而是會寫到內存中的鍵緩沖區,只有在清理鍵緩沖區或者關閉表的時候才會將對應的索引塊寫入到磁盤。這種方式可以極大的提升寫入性能,但是在數據或者主機崩潰時會造成索引損壞,需要執行修復操作。延遲更新索引的特性,可以在全局設置,也可以為單個表設置。

MyISAM壓縮表

如果表在創建并導入后,不會再進行修改操作,那么這樣的表或許適合采用MyISAM壓縮表。?

可以使用myisampack對MyISAM表進行壓縮(也叫打包pack)。壓縮表是不能進行修改的(除非先將表解除壓縮,修改數據,然后再次壓縮)。壓縮表可以極大地減少磁盤空間占用,因此也可以減少磁盤I/O,從而提升查詢性能。壓縮表也支持索引,但索引也是只讀的。
以現在的硬件能力,對大多數應用場景,讀取壓縮表數據時的解壓帶來的開銷影響并不大,而減少I/O帶來的好處則要大得多。壓縮時表中的記錄是獨立壓縮的,所以讀取單行的時候不需要去解壓整個表(甚至也不解壓行所在的整個頁面)。

MyISAM性能

MyISAM引擎設計簡單,數據以緊密格式存儲,所以在某些場景下的性能很好。MyISAM有一些服務器級別的性能擴展限制,比如對索引鍵緩沖區(key cache)的Mutex鎖,MariaDB基于段(segment)的索引緩沖區機制來避免該問題。但MyISAM最典型的性能問題還是表鎖的問題,如果你發現所有的查詢都長期處于“Locked”狀態,那么毫無疑問表鎖就是罪魁禍首。?

MySQL內建的其他存儲引擎

Archive引擎

Archive引擎只支持INSERT和SELECT操作,在MySQL5.1之前也不支持索引。Archive引擎會緩存所有的寫并利用zlib對插入的行進行壓縮,所以比MyISAM表的磁盤I/O更少。但是每次SELECT查詢都需要全表掃描。所以Archive表適合日志和數據采集類的應用,這類應用鎖數據分析時往往需要全表掃描,或者在一些需要快速INSERT操作的場合下也可以使用。

Archive引擎支持行級鎖和專用的緩沖區,所以可以實現高并發的插入。在一個查詢的開始直到返回表中存在所有行數之前,Archive引擎會阻止其他SELECT的執行,以實現一致性讀。另外,也實現了批量插入在完成之前對讀操作是不可見的。這種機制模仿了MVCC的一些特性。但Archive不是一個事務型引擎,而是一個針對高速插入和壓縮做了優化的簡單引擎。

Blackhole引擎

Blackhole引擎沒有實現任何的存儲機制,他會舍棄所有插入的數據,不做任何保存。但是服務器會記錄Blackhole表的日志,所以可以用于復制數據到備庫,或者只是簡單的記錄到日志。這種特殊的存儲引擎可以在一些特殊的復制框架和日志審核時發揮作用,但是也會存在很多問題,所以不推薦使用。

CSV引擎

CSV引擎可以將普通的CSV文件(逗號分割值的文件)作為MySQL的表來處理,但是這種表不支持索引。CSV引擎可以在數據庫運行時拷入或者拷出文件。可以將Excel等電子表格軟件中的數據存儲為CSV文件,然后復制到MySQL數據目錄下,就能在MySQL中打開使用。同樣,如果將數據寫入到一個CSV引擎表,其他外部程序也能立即從表的數據文件中讀取CSV格式的數據。因此CSV引擎可以作為一個數據交換的機制非常有用。

Federated引擎

Federated引擎是訪問其他MySQL服務器的一個代理,他會創建一個到遠程MySQL服務器的客戶端連接,并將查詢傳輸到遠程服務器執行,然后提取或者發送需要的數據。盡管該引擎看起來提供了一個很好的跨服務器靈活性,但是經常會帶來問題,因此默認是禁用的,后續改良版本FederatedX.

Memory引擎

如果需要快速訪問數據,并且這些數據不會被修改,重啟后丟失也沒關系,那么可以使用Memory表(以前也叫HEAP表)是非常有用的,Memory比MyISAM至少要快一個數量級,因為所有數據都保存在內存中,不需要進行磁盤I/O。Memory表在重啟后結構會保留,但是數據會丟失。

Memory表可以在很多場景發揮好的作用:

  • 用于查找(lookup)或者映射(mapping)表,如將郵編和州名映射的表。
  • 用于緩存周期性聚合數據(periodically aggregated data)的數據。
  • 用于保存數據分析中產生的中間數據。

Memory表支持Hash索引,因此查找操作非常快。雖然Memory速度非常快,但是還是無法替代基于磁盤的表。Memory是表級鎖,因此并發寫入的性能較低。他不支持BLOB以及TEXT類型的列,并且每行長度是固定的,所以即使指定了VARCHAR列,實際存儲的時候也會轉換成CHAR,這可能導致部分內存的浪費(一些限制基本在Percona版本基本解決)。?

如果MySQL在執行查詢的過程中需要使用臨時表來保存中間結果,內部使用的臨時表就是Memory表。如果中間結果太大超出了Memory限制,或者含有BLOB或TEXT字段,則臨時表會轉換成MyISAM表。

人們經常混淆Memory表或者臨時表,臨時表是指CREATE TEMPOARY TABLE語句創建的表,他可以使用任何存儲引擎,因此和Memory表不是一回事。臨時表只在單個連接可見,當連接斷開時,臨時表也將不復存在。

Merge引擎

Merge引擎是MyISAM引擎的一個變種。Merge表是由多個MyISAM表合成的虛擬表。如果將MySQL用于日志或者數據倉庫類應用,該引擎可以發揮作用。但是引入分區后,該引擎被放棄。

NDB集群引擎

MySQL服務器、NDB集群存儲引擎,以及分布式的、share-nothing的、容災的、高可用的NDB數據庫的組合,被稱為MySQL集群(MySQL-Cluster)。

選擇合適的引擎

大部分情況下InnoDB都是正確的選擇,所以Oracle在MySQL5.5版本時,將InnoDB作為默認的存儲引擎。除非使用到了某些InnoDB不具備的特性,并且沒有其他辦法可以替代,否則都應該優先考慮InnoDB引擎。例如需要使用全文索引,建議優先考慮InnoDB+Sphinx組合,而不是使用支持全文索引的MyISAM。當然如果不需要使用InnoDB的特性,同時其他特性能夠更好地滿足需求,可以考慮使用其他存儲引擎。

除非萬不得已,否則建議不要混合使用多種存儲引擎,否則可能會帶來一系列復雜的問題,以及一些潛在的bug和邊界問題。存儲引擎層和服務層的交互已經比較復雜,更不用說混合多個存儲引擎了。至少,混合存儲對一致性備份和服務器參數配置都帶來了困難。

如果應用需要不同的存儲引擎,請考慮以下幾個因素:

事務:如果需要事務支持,那么InnoDB(或者XtraDB)是目前最穩定并且經過驗證的選擇。如果不需要使用事務,并且主要是使用SELECT和INSERT操作,那么MyISAM是一個不錯的選擇。一般日志型的應用比較符合這一特性。

備份:備份的需求也會影響存儲引擎的選擇。如果可以定期的關閉服務器進行備份,那么備份的因素可以忽略。反之,如果需要在線熱備份,那么選擇InnoDB就是基本要求。

崩潰恢復:數據量比較大的時候,系統崩潰后如何快速恢復是一個需要考慮的問題。相對而言,MyISAM崩潰后發送損壞的概率比InnoDB要高很多,而且恢復速度也要慢。因此,即使不需要事務支持,很多人也選擇InnoDB引擎,這是一個非常重要的因素。

特有的特性:最后有些應用可能依賴一些存儲引擎所獨有的特性或者優化,比如很多應用依賴聚簇索引的優化。另外,MySQL中也只有MyISAM支持地理空間搜索。如果一個存儲引擎擁有一些關鍵的特性,同時又缺乏一些必要的特性,那么有時候就不得不做折中的考慮,或者在架構設計上做一些取舍。某些存儲引擎無法直接支持的特性,有時候可以通過變通也可以滿足需要。

日志型應用

假設你需要實時地記錄一臺中心電話交換機的每一通電話的日志到MySQL中。或者通過Apache的mod_log_sql模塊將網站的所有訪問信息自己記錄到表中。這一類的應用插入速度有很高的要求,數據庫不應該成為瓶頸。MyISMAM或者Archive存儲引擎對這類應用比較合適,因為它們開銷低,并且插入速度非常快。

如果需要對記錄的日志做分析報表,則事情就會變得有趣了。生成報表的SQL很有可能導致插入效率明顯降低,該怎么做呢?

一種解決方法,是利用MySQL內置的復制方案將數據復制一份到備庫,然后備份庫上執行比較消耗時間和CPU的查詢。這樣主庫只用于高效的插入工作,而備庫的查詢無須擔心影響到日志的插入性能。當然也可以在系統負載較低的時候執行報表查詢操作。但應用在不斷變化,如果依賴這個策略可能以后會導致問題。

另一種方法,在日志記錄表的名字中包含年和月的信息,比如web_log_2012_01或者web_log_2012_jan。這樣可以在已經沒有插入操作的歷史表上做頻繁的查詢操作,而不會干擾到最新的當前表上的插入操作。

只讀或者大部分情況下只讀的表

有些表的數據用于編制類目或者分列清單(如工作崗位、競拍、不動產等),這種應用的場景是典型的讀多寫少的業務。如果不介意MyISAM的崩潰問題,選用MyISAM引擎是合適的。不過不要低估崩潰恢復問題的重要性。有些存儲引擎不會保證數據完全寫入到磁盤中,而許多用戶實際上并不清楚這樣有多大風險(MyISAM只將數據寫到內存中,然后等待操作系統定期將數據刷出到磁盤上)。

一個值得推薦的方式,是在性能測試環境模擬真實的環境,運行應用,然后拔下電源模擬崩潰測試。對于崩潰恢復的第一手測試經驗是無價之寶,可以避免碰到真正的崩潰手足無措。?

不要輕易相信“MyISAM比InnoDB快”之類的經驗之談,這個結論往往不是絕對的。在很多已知的場景中,InnoDB的速度都可以讓MyISAM望塵莫及,尤其是使用到了聚簇索引,或者需要訪問的數據都可以放入到內存的應用。后面還會介紹更多影響存儲引擎性能的因素(如數據大小、I/O請求量,主鍵還是二級索引等)以及這些因素對應用的影響。

當設計上述類型的應用時,建議采用InnoDB,MyISAM引擎一開始可能沒有任何問題,但是隨著應用壓力的上升,則可能迅速惡化。各種鎖的爭用、崩潰后數據丟失的問題也都會隨之而來。

訂單處理

如果涉及訂單處理,那么支持事務就是必要選項。另外一個重要考慮點就是存儲引擎對外鍵的支持情況。InnoDB是訂單處理類應用最佳選擇。

電子公告牌和主題討論論壇

對于MySQL用戶,主題討論群是一個很有意思的話題。當前有成百上千的基于PHP或者Perl的免費系統可以支持主題討論。其中大部分的數據庫效率并不高,因為他們多大傾向于在一次請求中執行盡可能多的查詢語句。另外還有部分系統設計為不采用數據庫,當然也就無法利用到數據庫提供的一些方便的特性。主題討論區一般都有更新計數器,并且為各個主題計算訪問統計信息。多數應用只設計了幾張表保存所有的數據,所以核心表的讀寫壓力可能非常大。為保證這些核心表的數據一致性,鎖成為資源競爭的主要因素。

盡管有這些設計缺陷,但大多數應用在中低負載時可以工作的很好。如果web站點的規模迅速擴張,流量隨之猛增,則數據庫訪問可能變得非常慢。此時一個典型的解決方案是更改為更高讀寫的存儲引擎,但有時用戶會發現這么做反而導致系統變慢了。

用戶可能沒有意識到這是由于某些查詢的緣故,典型的如:

mysql> SELECT COUNT(*) FROM table;

?

問題就在于,不是所有的存儲引擎運行上述查詢都非常快:對于MyISAM確實會很快,其他的可能不行。每種存儲引擎都能找出類似對自己有利的例子,下一章將幫助用戶分析這些狀況,演示如何發現和解決存在的這類問題。  

CD-ROM應用

如果要發布一個基于CD-ROM或者DVD-ROM并且使用MySQL數據文件的應用,可以考慮使用MyISAM表或者MyISAM壓縮表,這樣的表之間可以隔離并且可以在不同介質上相互拷貝。MyISAM壓縮表比未壓縮的表要節約很多空間,但壓縮表是只讀的。在某些應用中可能是一個大問題。但是如果數據放到只讀介質的場景下,壓縮表的只讀特性就不是問題,就沒有理由不采用壓縮表的。

大數據量

什么樣的數據量算大?我們創建或者管理的很多InnoDB數據庫的數據量在3~5TB之間或者更大,這是單臺機器上的量,不是一個分片(shard)的量。這些系統運行還不錯,要做到這一點需要合理的選擇硬件,做好物理設計,并為服務器的I/O瓶頸做好規劃。在這樣的數據量下,如果采用MyISAM,崩潰后的恢復就是一個噩夢。

如果數據量繼續增長到10TB以上的級別,可能就需要建立數據倉庫。Infobright是MySQL數據倉庫最成功的解決方案。也有一些大數據庫不適合Infobright,卻可能適合TokuDB。

轉換表的引擎

有很多種方法可以將表的存儲引擎轉換成另外一種引擎。每種方法都有其優點和缺點。下面介紹其中的三種方法:?

ALTER TABLE

將表從一個引擎修改為另一個引擎最簡單的版本是使用ALTER TABLE語句。下面的語句將mytable的引擎修改為InnoDB:

mysql> create table mytable(name varchar(32)) ENGINE = MyISAM; Query OK, 0 rows affected (0.05 sec)mysql> SHOW TABLE STATUS LIKE 'mytable'\G; *************************** 1. row ***************************Name: mytableEngine: MyISAMVersion: 10Row_format: DynamicRows: 0Avg_row_length: 0Data_length: 0 Max_data_length: 281474976710655Index_length: 1024Data_free: 0Auto_increment: 1Create_time: 2018-10-07 03:58:03Update_time: 2018-10-07 03:58:03Check_time: NULLCollation: utf8mb4_0900_ai_ciChecksum: NULLCreate_options: Comment: 1 row in set (0.11 sec)mysql> ALTER TABLE mytable ENGINE=InnoDB; Query OK, 0 rows affected (0.05 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> SHOW TABLE STATUS LIKE 'mytable'\G; *************************** 1. row ***************************Name: mytableEngine: InnoDBVersion: 10Row_format: DynamicRows: 0Avg_row_length: 0Data_length: 0 Max_data_length: 281474976710655Index_length: 1024Data_free: 0Auto_increment: 1Create_time: 2018-10-07 03:59:16Update_time: 2018-10-07 03:58:03Check_time: NULLCollation: utf8mb4_0900_ai_ciChecksum: NULLCreate_options: Comment: 1 row in set (0.00 sec)

  

上述語法可以適用于任何存儲引擎。但是有一個問題:需要執行很長的時間。MySQL會按行將數據從原表復制到一張新的表中,在復制期間可能會消耗系統所有的I/O能力,同時原表上會加上讀鎖。所以,在繁忙的表上執行此操作需要特別小心。一個替代方案是采用接下來將要討論的導出導入的方法,手工進行表的復制。

如果轉換表的存引擎,將會失去原引擎相關的所有特性。例如,將InnoDB表轉為MyISAM表,再轉換為InnoDB,原InnoDB表上所有的外鍵將丟失。

導出與導入

為了更好控制轉換的過程,可以使用mysqldump工具將數據導出到文件,然后修改文件中的CREATE TABLE語句的存儲引擎選項,注意同時修改表名,因為同一個數據庫中不能存在相同的表名,即使他們使用的是不同的存儲引擎。同時還要注意mysqldump會默認在CREATE TABLE前加上DROP TABLE語句,不注意這一點可能會導致數據丟失。

創建與查詢(CREATE和SELECT)

第三種轉換的技術綜合了第一種方法的高效和第二種方法的安全。不需要導出整個表的數據,而是先創建一個新的存儲引擎表,然后利用INSERT ...SELECT語法來導數據:

創建存儲引擎為MyISAM的myisam_table表,并插入測試數據

mysql> create table myisam_table(name varchar(32)) ENGINE = MyISAM; Query OK, 0 rows affected (0.12 sec)mysql> insert into `myisam_table`(`name`) values('Amy'); Query OK, 1 row affected (0.01 sec)mysql> insert into `myisam_table`(`name`) values('John'); Query OK, 1 row affected (0.00 sec)mysql> insert into `myisam_table`(`name`) values('Rose'); Query OK, 1 row affected (0.01 sec)mysql> select * from myisam_table; +------+ | name | +------+ | Amy | | John | | Rose | +------+ 3 rows in set (0.00 sec)

  

創建和myisam_table存儲引擎一樣的innodb_table,并修改其存儲引擎

mysql> create table innodb_table like myisam_table; Query OK, 0 rows affected (0.07 sec)mysql> SHOW TABLE STATUS LIKE 'innodb_table'\G; *************************** 1. row ***************************Name: innodb_tableEngine: MyISAMVersion: 10Row_format: DynamicRows: 0Avg_row_length: 0Data_length: 0 Max_data_length: 281474976710655Index_length: 1024Data_free: 0Auto_increment: 1Create_time: 2018-10-07 04:09:37Update_time: 2018-10-07 04:09:37Check_time: NULLCollation: utf8mb4_0900_ai_ciChecksum: NULLCreate_options: Comment: 1 row in set (0.02 sec)mysql> select * from innodb_table; Empty set (0.00 sec)mysql> alter table innodb_table ENGINE=InnoDB; Query OK, 0 rows affected (0.07 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> SHOW TABLE STATUS LIKE 'innodb_table'\G; *************************** 1. row ***************************Name: innodb_tableEngine: InnoDBVersion: 10Row_format: DynamicRows: 0Avg_row_length: 0Data_length: 0 Max_data_length: 281474976710655Index_length: 1024Data_free: 0Auto_increment: 1Create_time: 2018-10-07 04:10:03Update_time: 2018-10-07 04:09:37Check_time: NULLCollation: utf8mb4_0900_ai_ciChecksum: NULLCreate_options: Comment: 1 row in set (0.00 sec)

  

使用INSERT ...SELECT語句將myisam_table的數據插入到innodb_table中

mysql> insert into innodb_table select * from myisam_table; Query OK, 3 rows affected (0.06 sec) Records: 3 Duplicates: 0 Warnings: 0mysql> select * from innodb_table; +------+ | name | +------+ | Amy | | John | | Rose | +------+ 3 rows in set (0.00 sec)

  

如果數據量不大的話,這樣工作很好。如果數據量很大,則可以考慮分批處理針對每一段數據執行事務提交操作,以避免大事務產生過多的undo。假設主鍵字段id,重復執行以下語句(最小值x和最大值y的進行相應替換)將數據導入到新表:

mysql> START TRANSACTION;mysql> INSERT INTO innodb_table SELECT * FROM myisam_table WHERE id BETWEEN x AND y;mysql> COMMIT;

  

這樣操作完成后,新表是原表的一個全量復制,原表還在,如果需要可以刪除原表。如果有必要可以在執行過程中對原表加鎖,以確保新表和原表的一致性。

轉載于:https://www.cnblogs.com/beiluowuzheng/p/9749315.html

總結

以上是生活随笔為你收集整理的MySQL之架构与历史(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。