myisam、innodb存儲引擎比較


MYSQL表類型(存儲引擎)



1.概述
MySQL數據庫其中一個特性是它的存儲引擎是插件式的。用戶能夠根據應用須要選擇存儲引擎。Mysql默認支持多種存儲引擎,以適用各類不一樣的應用須要。
默認狀況下,建立表不指定表的存儲引擎,則新表是默認存儲引擎的。能夠經過show engines來查看MySQL支持的存儲引擎和默認的存儲引擎。mysql


若是想改變默認的存儲引擎,能夠修改my.ini文件中的default-storage-engine。在建立新表的時候,能夠經過增長ENGINE關鍵字設置新表的存儲引擎。
如:
Create table ai{
id bigint(20) not null auto_increment,
primary key(id)
} ENGINE=MyISAM default charset=utf-8;
Create table bi{
id bigint(20) not null auto_increment,
primary key(id)
} ENGINE=InnoDB default charset=utf-8;


2.MyISAM
MyISAM不支持事務,不支持外鍵,其優點是訪問速度快,對事務完整性沒有要求或者以SELECT、INSERT爲主的應用基本上均可以使用這個引擎來建立表。
每一個MyISAM在磁盤上存儲成3個文件,其文件名都和表名相同,擴展名分別是:
.frm(存儲表定義);
MYD(MYData, 存儲數據);
MYI(MYIndex, 存儲索引)。
數據文件和索引文件能夠放置在不一樣的目錄,平均分佈IO,獲取更快的速度。
要指定索引文件和數據文件的路徑,須要在建立表的時候經過DATA DIRECTORY和INDEX DIRECTORY語句指定,文件路徑須要絕對路徑,而且具備訪問權限。
sql

3.InnoDB 數據庫

1) InnoDB概述
存儲引擎提供了具備提交,回滾和崩潰恢復能力的事務安全。可是對比MyISAM的存儲引擎,InnoDB寫的處理效率要差一些,而且會佔用更多的磁盤空間以保留數據和索引。InnoDB提供了行鎖(locking on row level),提供與 Oracle 類型一致的不加鎖讀取(non-locking read inSELECTs)。這些特性均提升了多用戶併發操做的性能表現。在InnoDB表中不須要擴大鎖定(lock escalation),由於InnoDB的列鎖定(row level locks)適宜很是小的空間。InnoDB 是 MySQL上第一個提供外鍵約束(FOREIGN KEY constraints)的表引擎。InnoDB 的設計目標是處理大容量數據庫系統,它的 CPU 利用率是其它基於磁盤的關係數據庫引擎所不能比的。在技術上,InnoDB是一套放在 MySQL後臺的完整數據庫系統,InnoDB 在主內存中創建其專用的緩衝池用於高速緩衝數據和索引。 InnoDB把數據和索引存放在表空間裏,可能包含多個文件,這與其它的不同,舉例來講,在MyISAM中,表被存放在單獨的文件中。InnoDB表的大小隻受限於操做系統的文件大小,通常爲 2 GB。表上處理着平均每秒 800 次的插入/更新的負載。
安全

2) 外鍵約束:
MySQL支持外鍵的存儲引擎只有InnoDB,在建立外鍵的時候,要求父表必須有對應的索引,子表在建立外鍵的時候也會自動建立對應的索引。
存儲方式:
InnoDB存儲表和索引有如下兩種方式。
使用共享表空間存儲,這種方式建立的表的表結構保存在.frm文件中,數據和索引保存在innodb_data_home_dir和innodb_data_file_path定義的表空間中,能夠是多個文件。
使用多表空間存儲,這種方式建立的表的表結構仍然保存在.frm文件中,可是每一個表的數據和索引單獨保存在.ibd中。若是是個分區表,則每一個分區對應單獨的.ibd文件,文件名是「表名+分區名」,能夠在建立分區的時候指定每一個分區的數據文件的位置,以此來將表的IO均勻分佈在多個磁盤上。
要使用多表空間的存儲方式,須要設置參數innodb_file_per_table,並重啓服務。
session

4. InnoDB最佳實踐
1). 主鍵應該儘量的短。
長主鍵浪費空間,主鍵儘可能要保證惟一。
2). 插入和更新應該使用主鍵順序
3). 增長log file size
當InnoDB把日誌文件寫滿了,會增長沒必要要的磁盤寫操做。
4). 避免大事務操做
事務太大會增長buffer pool, cpu的負累,測試發現,500次操做提交一次事務是最快速的,可是實際應用中,須要考慮到業務問題。
5). 避免大量插入
會在InnoDB表中影響關鍵碼壓縮併發

5.InnoDB行鎖
1) 概述
InnoDB行鎖是經過給索引上的索引項加鎖來實現的,這一點MySQL與ORACLE不一樣,後者是經過在數據塊中對相應數據行加鎖來實現的。InnoDB這種行鎖實現特色意味着:只有經過索引條件檢索數據,InnoDB才使用行級鎖,不然,InnoDB將使用表鎖!在實際應用中,要特別注意InnoDB行鎖的這一特性,否則的話,可能致使大量的鎖衝突,從而影響併發性能。
例子一,where條件中不是索引,出現了表鎖:
create table tab_no_index(id int,name varchar(10)) engine=innodb;
insert into tab_no_index values(1,'1'),(2,'2'),(3,'3'),(4,'4');
Session 1
Session 2
set autocommit=0;

select * from tab_no_index where id = 1 for update;


select * from tab_no_index where id = 2 for update;

等待
看起來session_1只給一行加了排他鎖,但session_2在請求其餘行的排他鎖時,卻出現了鎖等待!緣由就是在沒有索引的狀況下,InnoDB只能使用表鎖。
當咱們給其增長一個索引後,InnoDB就只鎖定了符合條件的行,
create table tab_with_index(id int,name varchar(10)) engine=innodb;
insert into tab_with_index values(1,'1'),(2,'2'),(3,'3'),(4,'4');
alter table tab_with_index add index id(id);
Session 1
Session 2
set autocommit=0;
set autocommit=0;
select * from tab_with_index where id = 1 for update;


select * from tab_with_index where id = 2 for update;

結果出來

1. 不經過索引來檢索數據時,innodb使用表鎖而不是行鎖;
table_locks_waited計數不會增長,innodb_row_lock_waits,table_locks_immediate加1。能夠經過show status like ‘%lock%’來查看。或者用show innodb status查看。
2. 因爲MySQL的行鎖是針對索引加的鎖,不是針對記錄加的鎖,因此雖然是訪問不一樣行的記錄,可是若是是使用相同的索引鍵,是會出現鎖衝突的。
3. 當表有多個索引的時候,不一樣的事務可使用不一樣的索引鎖定不一樣的行,另外,不管是使用主鍵索引、惟一索引或普通索引,InnoDB都會使用行鎖來對數據加鎖。
4. 即使在條件中使用了索引字段,可是否使用索引來檢索數據是由MySQL經過判斷不一樣執行計劃的代價來決定的,若是 MySQL認爲全表掃描效率更高,好比對一些很小的表,它就不會使用索引,這種狀況下InnoDB使用表鎖,而不是行鎖。
另外,在UPDATE、DELETE操做時,MySQL不只鎖定WHERE條件掃描過的全部索引記錄,並且會鎖定相鄰的鍵值,即所謂的next-key locking。
獲取InnoDB行鎖爭用狀況
show status like 'innodb_row_lock%';性能


若是發現鎖爭用比較嚴重,如InnoDB_row_lock_waits和InnoDB_row_lock_time_avg的值比較高,還能夠經過設置InnoDB Monitors來進一步觀察發生鎖衝突的表、數據行等,並分析鎖爭用的緣由。具體方法以下:

mysql> CREATE TABLE innodb_monitor(a INT) ENGINE=INNODB;
Query OK, 0 rows affected (0.14 sec)

而後就能夠用下面的語句來進行查看:
mysql> Show innodb status\G;

InnoDB 默認的事務隔離級是REPEATABLE READ。 SELECT ... FOR UPDATE, SELECT ... LOCK IN SHARE MODE, UPDATE, 和 DELETE ,這些以惟一條件搜索惟一索引的,只鎖定所找到的索引記錄,而不鎖定該索引以前的間隙。 不然這些操做將使用 next-key 鎖定,以 next-key 和 gap locks 鎖定找到的索引範圍,並阻塞其它用戶的新建插入。
1) 如何避免死鎖
死鎖是事務處理型數據庫系統的一個經典問題,可是它們並非很危險的, 除非它們如此地頻繁以致於你根本處理不了幾個事務。 當因死鎖而產生了回滾時,你一般能夠在你的應用程序中從新發出一個事務便可。
InnoDB 使用自動地行級鎖定。你可能剛好在插入或刪除單一一條記錄時產生死鎖。 這是由於這些操做並非真正「原子(atomic)」級的:他們會自動地在鎖定 inserted/deleted 行的索引記錄(可能有幾個)。

能夠經過下面所示的技巧來應付死鎖或減小死鎖的次數:
1) 使用 SHOW INNODB STATUS 來肯定引發最後一個死鎖的緣由。這能夠幫助你調整你的應用程序來避免死鎖。
2) 老是準備在因死鎖而發生錯誤時從新發出一個事務。死鎖並不危險。僅僅只需重試一遍。
3) 常常提交你的事務。小的事務有較少的碰撞可能。
4) 若是使用鎖定讀取 SELECT ... FOR UPDATE 或 ... LOCK IN SHARE MODE,儘可能使用較低的隔離級 READ COMMITTED。
5) 以一個固定秩序(a fixed order)訪問你的表和記錄。這樣事務將造成一個較精細的隊列,而避免死鎖。
6) 爲你的表添加合適的索引。那麼你的查詢只須要掃描較少的索引,於是設置較少的鎖定。使用 EXPLAIN SELECT 來肯定 MySQL 爲你的查詢挑選的適當的索引。
7) 儘可能少用鎖定:若是能夠經過一個 SELECT 在一個較老的數據快照中得到所需數據,就不要再添加子句 FOR UPDATE 或 LOCK IN SHARE MODE 。在這時使用 READ COMMITTED 隔離級是較好的主意,由於在同一個事務中的每一個 consistent read 只讀取它最早肯定的數據快照。測試

6. MyISAM or InnoDB?
InnoDB和MyISAM是在使用MySQL最經常使用的兩個表類型,各有優缺點,視具體應用而定。基本的差異爲:MyISAM類型不支持事務處理等高級處理,而InnoDB類型支持。MyISAM類型的表強調的是性能,其執行速度比InnoDB類型更快,可是不提供事務支持,而InnoDB提供事務支持以及外部鍵等高級數據庫功能。

MyISAM:若是應用是以讀操做和插入操做爲主,只有不多的更新和刪除操做,而且對事務的完整性、併發性要求不是很高,那麼選擇MyISAM是很是適合的。MyISAM在數據倉庫下是最經常使用使用的存儲引擎之一。
InnoDB:用於事務處理應用程序,支持外鍵。若是應用對事務的完整性有比較高的要求,在併發條件下要求數據的一致性,數據操做除了插入和查詢之外,還包括不少的更新、刪除操做,那麼InnoDB存儲引擎應該是比較合適的選擇。InnoDB存儲引擎除了有效地下降因爲刪除和更新致使的鎖定,還能夠確保事務的完整性提交和回滾。
兩種類型最主要的差異就是InnoDB 支持事務處理與外鍵和行級鎖。而MyISAM不支持。
MyISAM的索引和數據是分開的,而且索引是有壓縮的,內存使用率就對應提升了很多。能加載更多索引,而InnoDB是索引和數據是緊密捆綁的,沒有使用壓縮從而會形成InnoDB比MyISAM體積龐大不小。
InnoDB不只僅只是行鎖,select count(*) 和order by這種操做Innodb其實也是會鎖表的, Innodb雖然是行級鎖,可是那個只是where對它主鍵是有效,非主鍵的都會鎖全表的。
InnoDB 中不保存表的具體行數,也就是說,執行select count(*) from table時,InnoDB要掃描一遍整個表來計算有多少行,可是MyISAM只要簡單的讀出保存好的行數便可。注意的是,當count(*)語句包含 where條件時,兩種表的操做是同樣的。
InnoDB表的行鎖也不是絕對的,若是在執行一個SQL語句時MySQL不能肯定要掃描的範圍,InnoDB表一樣會鎖全表。
對於AUTO_INCREMENT類型的字段,InnoDB中必須包含只有該字段的索引,可是在MyISAM表中,能夠和其餘字段一塊兒創建聯合索引。
DELETE FROM table時,InnoDB不會從新創建表,而是一行一行的刪除。


atom

相關文章
相關標籤/搜索