本篇把MySQL最經常使用的存儲引擎給你們作一個介紹,而後經過插入、修改和併發實驗來了解和驗證一下它們之間的一些差別。php
1、MySQL存儲引擎簡介
存儲引擎在MySQL結構裏佔據核心的位置,是上層抽象接口和存儲的物理文件之間的橋樑。每一種storage engine 架構組件都是根據特定的場合來設計的,負責數據的 I/O 操做,並啓用一些特性的支持。
mysql
MySQL存儲引擎被設計爲插件式結構,每種存儲引擎可從運行的mysql裏動態加載或卸載。咱們能夠在客戶端鏈接後用show plugins;查看當前加載的插件,用install plugin xxx;或者 uninstall plugin xxx;來安裝或卸載。linux
查看服務器當前支持的引擎命令:
mysql> show engines;sql
主要的幾種引擎介紹以下:
InnoDB:支持事務操做,支持行級鎖,支持外鍵。獨立表結構的花每一個表單文件存儲,是MySQL5.5以後的默認引擎。
MyISAM:使用普遍,數據量不是特別大時性能很高,是5.5以前的默認引擎。
Memory:數據直接放在內存,極快的訪問速度,可是空間很受限。
MRG_MYISAM:能夠把MyISAM表分組管理。
Federated:能夠把不一樣物理服務器鏈接成一個邏輯服務器,適合分佈式管理。
CSV:導入導出成CSV格式,便於和其餘軟件數據交換。數據庫
咱們能夠配置php.ini文件或者在server啓動時,能夠經過--default-storage-engine參數來指定默認的存儲引擎。也能夠在mysql運行狀態下動態改變默認引擎:
show variables like 'default_storage_engine';
SET default_storage_engine=MYISAM;apache
數據庫的每一個表可使用不一樣的引擎:
create table t_a(uid int,uname varchar(50)) engine=innodb;
也能夠動態修改表的引擎:
alter table t_a engine=MyISAM;segmentfault
2、MySQL存儲引擎的文件組成與備份
MySQL主要的動態文件有日誌文件、配置文件和存儲引擎的數據文件
一、日誌文件
種類很是多,咱們也能夠在這些變量裏找到innodb的特殊日誌文件:
show variables like '%log%';
二、配置和鏈接文件
my.cnf是數據庫的主要配置文件,若是咱們作了主從配置,則還有master.info等配置信息文件。
linux下支持tcp和socket鏈接,能夠經過配置my.cnf或者鏈接時增長參數來肯定mysql --protocol=tcp,若是是socket方式則通常會經過socket文件來鏈接/tmp/mysql.sock。
三、數據文件
每一種存儲引擎都有.frm 表元數據文件。而後每種引擎都有本身的一些特有特有格式的文件:
.myd (MyData)是MyISAM數據文件,.myi (MyIndex)是MyISAM索引文件(b-tree、full-text等)。
innodb的共享表空間存在ibdata文件裏,若是配置成獨享表空間的話(mysql默認)每一個表還會有對應.ibb文件。咱們能夠經過變量查詢和設置這些配置:
show variables like ‘%innodb%’; 其中innodb_file_per_table設置是不是獨享表空間,innodb_data_file_path 和innodb_data_home_dir用來指定表的存放位置。緩存
備份:
一、邏輯備份
邏輯備份是不停機的狀況下比較好的備份方式,經過mysqldump或者其餘方式來導出sql語句。
二、物理備份
物理備份在某些狀況是更加直接和快速的方式。myisam引擎由於是非事務沒有獨立日誌,通常備份3個文件便可,也能夠經過mysqlhotcopy來進行物理備份。
innodb 由於事物須要有日誌文件,若是在運行狀態則不能手工來備份,須要一些商業化的工具好比ibbackup來支持物理備份。
三、主從物理備份
由於物理備份通常須要鎖庫,在線上數據庫上咱們若是設置了主從服務器而且有多臺從庫的話,能夠暫停一臺從庫,而後實行物理備份。服務器
3、插入和更新數據
咱們先建立3個引擎的數據表user_myisam、user_innodb、user_memory,表的結構是同樣的:session
create table user_myisam ( uid int auto_increment, uname varchar(50) not null default '', type tinyint not null default 0, ctime timestamp not null default current_timestamp, primary key (uid) ) engine=myisam, charset=utf8;
咱們在生成數據時,可使用一條條數據插入、導入sql文件、或者批量插入的方式進行。
導入sql文件是有大小限制的,咱們能夠經過max_allowed_packet變量來查看,通常默認爲1M,因此導入大量數據時須要增大這個變量:
show variables like 'max_allowed_packet';
顯然,數據量很大時,批量插入的方式是效率最高的:
insert into tbl values(),(),()...
通過對比,雖然memory引擎插入和查詢修改的速度都極快,單隻支持幾萬行數據,即便調大了內存參數也只能支持10多萬行。因此memory通常用在一些數據量比較小的特殊場合,好比在線用戶表、或者緩存一些配置信息等。
咱們用批量插入的方式把myisam和innodb的表各插入了1千萬行數據(每次插入1萬行或更多),myisam的速度要稍快些,沒有調優的狀況下幾分鐘時間就能夠了。
更新和查詢的數據對比:
在一個進程操做的狀況下,myisam的更新和查詢速度都會稍快於innodb。
特別注意的一點是,innodb查詢表的行數須要全表掃描,速度會很是慢,查詢1千萬行數據的表最多時要六、7s,因此在項目裏必定要控制innodb表的總數查詢,必定要緩存。而myisam由於保存了總行數是極快的。
4、innodb的事務支持和鎖
innodb的事物支持4種隔離級別:
read uncommitted:髒讀,在本身的事務裏能看到別的事務修改但未提交的數據。
read committed:不可重複讀,雖然別的事務未提交的數據看不到,可是提交後就能夠了,因此不能屢次讀取,數據可能不一致。
repeatable read:可重複讀,事務作了隔離,但仍是能夠併發的。
serializable:串行,最嚴格的方式,事務單行處理,不會並行。
查看當前和全局的事務隔離級別:
SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
能夠經過如下命令來改變設置:
set global transaction isolation level read uncommitted;
咱們能夠經過2個session而後設置set autocommit=0來進行測試和驗證這4種事務隔離級別的差異,在本身的項目裏也能夠根據狀況來改變。越高的隔離級別對性能影響越大,innodb默認是repeatable read方式。
mysql有3種鎖:
一、表級鎖:myisam的默認形式,開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的機率最高,併發度最低。能夠查看錶鎖的一些狀況:
show status like 'table%';
二、行級鎖:innodb的默認形式,開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。
須要注意的是,innodb只有在能利用索引的操做時才執行行級鎖,若是查詢或更新操做不能利用索引仍是會使用表級鎖的。查看行鎖狀態:
show status like 'innodb_row_lock%';
三、頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度通常。
5、併發測試與參數調優總結
雖然在上面單進程的狀況下,myisam在插入查詢和更新等操做中性能都比較高,可是在咱們模擬高併發的狀況下,能夠看出innodb的銷量明顯佔優了。
咱們用apache的ab工具來測試3000次30個併發的請求,每一個請求在1千萬數據裏隨機找5行數據進行修改和查詢(用到索引),測試結果以下:
myisam的測試數據:
innodb的測試結果:
myisam的一些參數優化:
read_buffer_size緩存大小
設置concurrent_insert爲2,在尾部插入數據,不影響select
打開delay_key_write
innodb的一些參數:
設置事務提交後數據保存方式:
innodb_flush_log_at_trx_commit
0 每秒保存 1 每事務保存 2 系統決定
innodb_buffer_pool緩存大小:
show status like 'innodb_buffer_pool%';
能夠用show engine innodb status\G查看innodb的一些狀況:
innodb_read_io_threads讀寫進程數
innodb_write_io_threads
innodb_io_capacity合併寫入數量
innodb_io_capacity=5000;
set global innodb_stats_on_metadata=0;關閉元數據更新
通過咱們的一些操做對比,能夠看出: Memory雖然是高效的引擎,可是因爲是臨時數據並且有數據量的限制,適合與性能要求高數據量小的地方,和緩存的效果相似。 MyISAM適合數據量不是特別大併發不過高的大部分場合,性能都佔優,而且也支持全文檢索。若是不須要事務支持的話MyISAM絕對是最優的方式。 而InnoDB 則更適合與大併發大數據量的場合,除了支持事務,在高併發時行級鎖的優點就會發揮出來。固然咱們須要在代碼和設計裏去規避innodb自己的一些的問題,例如儘量使用到索引,緩存表的行數等。