MyISAM 與 innoDB 的選擇

一、MyISAM:默認表類型,它是基於傳統的ISAM類型,ISAM是Indexed Sequential Access Method (有索引的順序訪問方法) 的縮寫,它是存儲記錄和文件的標準方法。不是事務安全的,並且不支持外鍵,若是執行大量的select,insert MyISAM比較適合。mysql

二、InnoDB:支持事務安全的引擎,支持外鍵、行鎖、事務是他的最大特色。若是有大量的update和insert,建議使用InnoDB,特別是針對多個併發和QPS較高的狀況。linux

 

1、表鎖差別sql

MyISAM:數據庫

myisam只支持表級鎖,用戶在操做myisam表時,select,update,delete,insert語句都會給表自動加鎖,若是加鎖之後的表知足insert併發的狀況下,能夠在表的尾部插入新的數據。也能夠經過lock table命令來鎖表,這樣操做主要是能夠模仿事務,可是消耗很是大,通常只在實驗演示中使用。緩存

InnoDB :安全

Innodb支持事務和行級鎖,是innodb的最大特點。服務器

事務的ACID屬性:atomicity,consistent,isolation,durable。多線程

併發事務帶來的幾個問題:更新丟失,髒讀,不可重複讀,幻讀。併發

事務隔離級別:未提交讀(Read uncommitted),已提交讀(Read committed),可重複讀(Repeatable read),可序列化(Serializable)函數

四種隔離級別的比較

讀數據一致性及併發反作用

 

隔離級別

讀數據一致性

髒讀

不可重複讀

幻讀

爲提交讀(read uncommitted)

最低級別,不讀物理上順壞的數據

已提交讀(read committed)

語句級

可重複讀(Repeatable red)

事務級

可序列化(Serializable)

最高級別,事務級

 

查看mysql的默認事務隔離級別「show global variables like ‘tx_isolation’; 」

Innodb的行鎖模式有如下幾種:共享鎖,排他鎖,意向共享鎖(表鎖),意向排他鎖(表鎖),間隙鎖。

注意:當語句沒有使用索引,innodb不能肯定操做的行,這個時候就使用的意向鎖,也就是表鎖

關於死鎖:

什麼是死鎖?當兩個事務都須要得到對方持有的排他鎖才能完成事務,這樣就致使了循環鎖等待,也就是常見的死鎖類型。

解決死鎖的方法:

一、  數據庫參數

二、  應用中儘可能約定程序讀取表的順序同樣

三、  應用中處理一個表時,儘可能對處理的順序排序

四、  調整事務隔離級別(避免兩個事務同時操做一行不存在的數據,容易發生死鎖)

 

2、數據庫文件差別

MyISAM :

myisam屬於堆表

myisam在磁盤存儲上有三個文件,每一個文件名以表名開頭,擴展名指出文件類型。

.frm 用於存儲表的定義

.MYD 用於存放數據

.MYI 用於存放表索引

myisam表還支持三種不一樣的存儲格式:

靜態表(默認,可是注意數據末尾不能有空格,會被去掉)

動態表

壓縮表

InnoDB :

innodb屬於索引組織表

innodb有兩種存儲方式,共享表空間存儲和多表空間存儲

兩種存儲方式的表結構和myisam同樣,以表名開頭,擴展名是.frm。

若是使用共享表空間,那麼全部表的數據文件和索引文件都保存在一個表空間裏,一個表空間能夠有多個文件,經過innodb_data_file_path和innodb_data_home_dir參數設置共享表空間的位置和名字,通常共享表空間的名字叫ibdata1-n。

若是使用多表空間,那麼每一個表都有一個表空間文件用於存儲每一個表的數據和索引,文件名以表名開頭,以.ibd爲擴展名。

 

3、索引差別

一、關於自動增加

myisam引擎的自動增加列必須是索引,若是是組合索引,自動增加能夠不是第一列,他能夠根據前面幾列進行排序後遞增。

innodb引擎的自動增加咧必須是索引,若是是組合索引也必須是組合索引的第一列。

二、關於主鍵

myisam容許沒有任何索引和主鍵的表存在,

myisam的索引都是保存行的地址。

innodb引擎若是沒有設定主鍵或者非空惟一索引,就會自動生成一個6字節的主鍵(用戶不可見)

innodb的數據是主索引的一部分,附加索引保存的是主索引的值。

三、關於count()函數

myisam保存有表的總行數,若是select count(*) from table;會直接取出出該值

innodb沒有保存表的總行數,若是使用select count(*) from table;就會遍歷整個表,消耗至關大,可是在加了wehre       條件後,myisam和innodb處理的方式都同樣。

四、全文索引

myisam支持 FULLTEXT類型的全文索引

innodb不支持FULLTEXT類型的全文索引,可是innodb可使用sphinx插件支持全文索引,而且效果更好。(sphinx   是一個開源軟件,提供多種語言的API接口,能夠優化mysql的各類查詢)

五、delete from table

使用這條命令時,innodb不會重新創建表,而是一條一條的刪除數據,在innodb上若是要清空保存有大量數據的表,最       好不要使用這個命令。(推薦使用truncate table,不過須要用戶有drop此表的權限)

六、索引保存位置

myisam的索引以表名+.MYI文件分別保存。

innodb的索引和數據一塊兒保存在表空間裏。

 

4、開發的注意事項

一、能夠用 show create table tablename 命令看錶的引擎類型。

二、對不支持事務的表作start/commit操做沒有任何效果,在執行commit前已經提交。

三、能夠執行如下命令來切換非事務表到事務(數據不會丟失),innodb表比myisam表更安全:alter table tablename type=innodb;或者使用 alter table tablename engine = innodb;

四、默認innodb是開啓自動提交的,若是你按照myisam的使用方法來編寫代碼頁不會存在錯誤,只是性能會很低。如何在編寫代碼時候提升數據庫性能呢?

a、儘可能將多個語句綁到一個事務中,進行提交,避免屢次提交致使的數據庫開銷。

b、在一個事務得到排他鎖或者意向排他鎖之後,若是後面還有須要處理的sql語句,在這兩條或者多條sql語句之間程序應儘可能少的進行邏輯運算和處理,減小鎖的時間。

c、儘可能避免死鎖

d、sql語句若是有where子句必定要使用索引,儘可能避免獲取意向排他鎖。

f、針對咱們本身的數據庫環境,日誌系統是直插入,不修改的,因此咱們使用混合引擎方式,ZION_LOG_DB照舊使用myisam存儲引擎,只有ZION_GAME_DB,ZION_LOGIN_DB,DAUM_BILLING使用Innodb引擎。

 

5、究竟該怎麼選擇

下面先讓咱們回答一些問題:   

◆你的數據庫有外鍵嗎?   

◆你須要事務支持嗎?   

◆你須要全文索引嗎?   

◆你常用什麼樣的查詢模式?   

◆你的數據有多大?   
  
myisam只有索引緩存   
innodb不分索引文件數據文件 innodb buffer   
myisam只能管理索引,在索引數據大於分配的資源時,會由操做系統來cache;數據文件依賴於操做系統的cache。innodb無論是索引仍是數據,都是本身來管理  
  
思考上面這些問題可讓你找到合適的方向,但那並非絕對的。若是你須要事務處理或是外鍵,那麼InnoDB 多是比較好的方式。若是你須要全文索引,那麼一般來講 MyISAM是好的選擇,由於這是系統內建的,然而,咱們其實並不會常常地去測試兩百萬行記錄。因此,就算是慢一點,咱們能夠經過使用Sphinx從InnoDB中得到全文索引。  
  
數據的大小,是一個影響你選擇什麼樣存儲引擎的重要因素,大尺寸的數據集趨向於選擇InnoDB方式,由於其支持事務處理和故障恢復。數據庫的在小決定了故障恢復的時間長短,InnoDB能夠利用事務日誌進行數據恢復,這會比較快。而MyISAM可能會須要幾個小時甚至幾天來幹這些事,InnoDB只須要幾分鐘。  
  
操做數據庫表的習慣可能也會是一個對性能影響很大的因素。好比: COUNT() 在 MyISAM 表中會很是快,而在InnoDB 表下可能會很痛苦。而主鍵查詢則在InnoDB下會至關至關的快,但須要當心的是若是咱們的主鍵太長了也會致使性能問題。大批的inserts 語句在 MyISAM下會快一些,可是updates 在InnoDB下會更快一些——尤爲在併發量大的時候。  
  
因此,到底你檢使用哪個呢?根據經驗來看,若是是一些小型的應用或項目,那麼MyISAM 也許會更適合。固然,在大型的環境下使用 MyISAM 也會有很大成功的時候,但卻不老是這樣的。若是你正在計劃使用一個超大數據量的項目,並且須要事務處理或外鍵支持,那麼你真的應該直接使用 InnoDB方式。但須要記住InnoDB 的表須要更多的內存和存儲,轉換100GB 的MyISAM 表到InnoDB 表可能會讓你有很是壞的體驗。  
  
對於支持事務的InnoDB類型的表,影響速度的主要緣由是AUTOCOMMIT默認設置是打開的,並且程序沒有顯式調用BEGIN 開始事務,致使每插入一條都自動Commit,嚴重影響了速度。能夠在執行sql前調用begin,多條sql造成一個事務(即便autocommit打開也能夠),將大大提升性能。  

 

InnoDB

InnoDB 給 MySQL 提供了具備事務(commit)、回滾(rollback)和崩潰修復能力 (crash recovery capabilities)的事務安全(transaction-safe (ACID compliant))型表。 InnoDB 提供了行鎖(locking on row level),提供與 Oracle 類型一致的不加鎖讀取(non- locking read in SELECTs)。這些特性均提升了多用戶併發操做的性能表現。在InnoDB表中不須要擴大鎖定 (lock escalation),由於 InnoDB 的列鎖定(row level locks)適宜很是小的空間。 InnoDB 是 MySQL 上第一個提供外鍵約束(FOREIGN KEY constraints)的表引擎。  

InnoDB 的設計目標是處理大容量數據庫系統,它的 CPU 利用率是其它基於磁盤的關係數據庫引擎所不能比的。在技術上,InnoDB 是一套放在 MySQL 後臺的完整數據庫系統,InnoDB 在主內存中創建其專用的緩衝池用於高速緩衝數據和索引。 InnoDB 把數據和索引存放在表空間裏,可能包含多個文件,這與其它的不同,舉例來講,在 MyISAM 中,表被存放在單獨的文件中。InnoDB 表的大小隻受限於操做系統的文件大小,通常爲 2 GB。  
InnoDB全部的表都保存在同一個數據文件 ibdata1 中(也多是多個文件,或者是獨立的表空間文件),相對來講比較很差備份,免費的方案能夠是拷貝數據文件、備份 binlog,或者用 mysqldump。  


MyISAM   
MyISAM 是MySQL缺省存貯引擎 .   
每張MyISAM 表被存放在三個文件 。frm 文件存放表格定義。 數據文件是MYD (MYData) 。 索引文件是 MYI (MYIndex) 引申。   
由於MyISAM相對簡單因此在效率上要優於InnoDB..小型應用使用MyISAM是不錯的選擇.   
MyISAM表是保存成文件的形式,在跨平臺的數據轉移中使用MyISAM存儲會省去很多的麻煩   
  
如下是一些細節和具體實現的差異:   
  
1.InnoDB不支持FULLTEXT類型的索引。   
2.InnoDB 中不保存表的具體行數,也就是說,執行select count(*) from table時,InnoDB要掃描一遍整個表來計算有多少行,可是MyISAM只要簡單的讀出保存好的行數便可。注意的是,當count(*)語句包含 where條件時,兩種表的操做是同樣的。  
3.對於AUTO_INCREMENT類型的字段,InnoDB中必須包含只有該字段的索引,可是在MyISAM表中,能夠和其餘字段一塊兒創建聯合索引。   
4.DELETE FROM table時,InnoDB不會從新創建表,而是一行一行的刪除。   
5.LOAD TABLE FROM MASTER操做對InnoDB是不起做用的,解決方法是首先把InnoDB表改爲MyISAM表,導入數據後再改爲InnoDB表,可是對於使用的額外的InnoDB特性(例如外鍵)的表不適用。  

另外,InnoDB表的行鎖也不是絕對的,若是在執行一個SQL語句時MySQL不能肯定要掃描的範圍,InnoDB表一樣會鎖全表,例如 update table set num=1 where name like 「%aaa%」  

任何一種表都不是萬能的,只用恰當的針對業務類型來選擇合適的表類型,才能最大的發揮MySQL的性能優點。   

 

6、重複地總結一遍

一、MyISAM不支持事務,InnoDB是事務類型的存儲引擎,當咱們的表須要用到事務支持的時候,那確定是不能選擇MyISAM了。

二、MyISAM只支持表級鎖,BDB支持頁級鎖和表級鎖默認爲頁級鎖,而InnoDB支持行級鎖和表級鎖默認爲行級鎖
 
表級鎖:直接鎖定整張表,在鎖按期間,其餘進程沒法對該表進行寫操做,若是設置的是寫鎖,那麼其餘進程讀也不容許
 
MyISAM是表級鎖定的存儲引擎,它不會出現死鎖問題
 
對於write,表鎖定原理以下:
 
若是表上沒有鎖,在其上面放置一個寫鎖,不然,把鎖定請求放在寫鎖隊列中。
 
對於read,表鎖定原理以下 :
 
若是表上沒有寫鎖定,那麼把一個讀鎖放在其上面,不然把鎖請求放在讀鎖定隊列中
 
當一個鎖定被釋放時,表可被寫鎖定隊列中的線程獲得,而後纔是讀鎖定隊列中的線程。這意味着,若是你在一個表上有許多更新,那麼你的SELECT語句將等到全部的寫鎖定線程執行完。

行級鎖:只對指定的行進行鎖定,其餘進程仍是能夠對錶中的其餘行進行操做的。
 
行級鎖是Mysql粒度最小的一種鎖,它能大大的減小數據庫操做的衝突,可是粒度越小實現成本也越大。
 
行級鎖可能會致使「死鎖」,那究竟是怎麼致使的呢,分析緣由:Mysql行級鎖並非直接鎖記錄,而是鎖索引。索引分爲主鍵索引和非主鍵索引兩種,若是一條sql語句操做了主鍵索引,那麼Mysql就會鎖定這個主鍵索引,若是sql語句操做的是非主鍵索引,那麼Mysql會先鎖定這個非主鍵索引,再去鎖定主鍵索引。
 
在UPDATE 和 DELETE操做時Mysql不只會鎖定全部WHERE 條件掃描過得索引,還會鎖定相鄰的鍵值。
 
「死鎖」舉例分析:
 
表Test:(ID,STATE,TIME)  主鍵索引:ID  非主鍵索引:STATE
 
當執行"UPDATE  STATE =1011 WHERE STATE=1000"  語句的時候會鎖定STATE索引,因爲STATE 是非主鍵索引,因此Mysql還會去請求鎖定ID索引
 
當另外一個SQL語句與語句1幾乎同時執行時:「UPDATE STATE=1010 WHERE ID=1」  對於語句2 Mysql會先鎖定ID索引,因爲語句2操做了STATE字段,因此Mysql還會請求鎖定STATE索引。這時。彼此鎖定着對方須要的索引,又都在等待對方釋放鎖定。因此出現了"死鎖"的狀況。
 
行級鎖的優勢:
 
有許多線程訪問不一樣的行時,只存在少許的衝突。
 
回滾時只有少許的更改
 
能夠長時間鎖定單一的行
 
行級鎖缺點:
 
相對於頁級鎖和表級鎖來講佔用了更多的內存
 
當表的大部分行在使用時,比頁級鎖和表級鎖慢,由於你必須得到更多的鎖
 
當在大部分數據上常用GROUP BY操做,確定會比表級鎖和頁級鎖慢。
 
頁級鎖:表級鎖速度快,可是衝突多;行級鎖速度慢,但衝突少;頁級鎖就是他倆折中的,一次鎖定相鄰的一組記錄。

三、MyISAM引擎不支持外鍵,InnoDB支持外鍵

四、MyISAM引擎的表在大量高併發的讀寫下會常常出現表損壞的狀況
 
咱們之前作的項目就遇到這個問題,表的INSERT 和 UPDATE操做很頻繁,原來用的MyISAM引擎,致使表隔三差五就損壞,後來更換成了InnoDB引擎。
 
其餘容易致使表損壞緣由:
 
服務器忽然斷電致使數據文件損壞,強制關機(mysqld未關閉狀況下)致使表損壞
 
mysqld進程在寫入操做的時候被殺掉
 
磁盤故障
 
表損壞常見症狀:
 
查詢表不能返回數據或返回部分數據
 
打開表失敗: Can’t open file: ‘×××.MYI’ (errno: 145) 。
 
Error: Table 'p' is marked as crashed and should be repaired 。

Incorrect key file for table: '...'. Try to repair it
 
Mysql表的恢復:

對於MyISAM表的恢復:

可使用Mysql自帶的myisamchk工具: myisamchk -r tablename  或者 myisamchk -o tablename(比前面的更保險) 對錶進行修復

五、對於count()查詢來講MyISAM更有優點

由於MyISAM存儲了表中的行數記錄,執行SELECT COUNT() 的時候能夠直接獲取到結果,而InnoDB須要掃描所有數據後獲得結果。

可是注意一點:對於帶有WHERE 條件的 SELECT COUNT()語句兩種引擎的表執行過程是同樣的,都須要掃描所有數據後獲得結果

六、 InnoDB是爲處理巨大數據量時的最大性能設計,它的CPU效率多是任何其它基於磁盤的關係數據庫引擎所不能匹敵的。

七、MyISAM支持全文索引(FULLTEXT),InnoDB不支持

八、MyISAM引擎的表的查詢、更新、插入的效率要比InnoDB高

網上截取了前輩們測試結論: 

測試方法:連續提交10個query, 表記錄總數:38萬 , 時間單位 s
 
        引擎類型                    MyISAM                InnoDB              性能相差
 
        count                      0.0008357            3.0163                3609
 
        查詢主鍵                  0.005708              0.1574                27.57
 
        查詢非主鍵                  24.01                  80.37                3.348
 
        更新主鍵                  0.008124            0.8183                100.7
 
        更新非主鍵                0.004141            0.02625              6.338
 
        插入                        0.004188            0.3694                88.21
 

    (1)加了索引之後,對於MyISAM查詢能夠加快:4 206.09733倍,對InnoDB查詢加快510.72921倍,同時對MyISAM更新速度減慢爲原來的1/2,InnoDB的更
  新速度減慢爲原來的1/30。要看狀況決定是否要加索引,好比不查詢的log表,不要作任何的索引。
 
    (2)若是你的數據量是百萬級別的,而且沒有任何的事務處理,那麼用MyISAM是性能最好的選擇。
 
    (3)InnoDB表的大小更加的大,用MyISAM可省不少的硬盤空間。
 
        在咱們測試的這個38w的表中,表佔用空間的狀況以下:
            引擎類型                    MyISAM              InnoDB
            數據                      53,924 KB          58,976 KB
            索引                      13,640 KB          21,072 KB
            佔用總空間              67,564 KB          80,048 KB
  
        另一個176W萬記錄的表, 表佔用空間的狀況以下:
 
            引擎類型                MyIsam              InnorDB
            數據                  56,166 KB          90,736 KB
            索引                  67,103 KB          88,848 KB
            佔用總空間        123,269 KB        179,584 KB

 

7、性能對比

 

測試的版本是mysql  Ver 14.14 Distrib 5.1.49, for debian-linux-gnu (i686),使用的是Innodb plugin 1.0.8(官方稱比built-in版本性能更好)和默認的MyISAM。

測試機器是筆記本,配置以下:Intel 酷睿2雙核 P8600,2G*2 DDR3 1066內存,320G硬盤5400轉。

測試一:數據插入性能測試,這裏我分別對innodb_flush_log_at_trx_commit參數打開和關閉都測了了一下,每次測試都是運行40s,表中數字都是實際插入條數。

                       MyISAM                 Innodb (打開)      Innodb (關閉)

單線程,逐個插入         120000                 60000              60000

4線程,逐個插入          40000*4                20000*4            40000*4

單線程,批量100條/次插入  3600*100               800*100            3000*100

單線程,批量200條/次插入  1800*200               400*200            1600*200

能夠發現批量插入的性能遠高於單條插入,可是一次批量的大小對性能影響不大。每條記錄是否都刷新日誌的參數對innodb性能的影響巨大。整體上來講,MyISAM性能更優一點。這裏有一點須要注意,在插入測試過程當中,我對系統資源進行了監控,發現MyISAM對系統資源佔用很低,可是Innodb對磁盤佔用卻很高,應該是對事務控制多了不少須要記錄的日誌。

測試二:數據讀取性能測試。每次隨機讀取1000條記錄,反覆進行讀取。

                        MyISAM        Innodb

單線程,200次讀取         5.7s          16.7s

4線程,200次讀取          12s           40.8s

能夠看出MyISAM的讀取性能很是恐怖,性能差距在3倍的樣子。

以上兩個測試發現MyISAM在無事務的需求下幾乎完勝,可是要知道它是表鎖,Innodb是行鎖,那麼在併發讀寫同時存在的狀況下,那結果會是怎麼樣呢?!

測試三:兩個線程併發寫入,2個線程併發讀取。

                       MyISAM                                 Innodb

逐個插入                寫入40s:10000*2 讀取200次*2:14s        寫入40s:60000*2 讀取200次*2:50s

批量100條/次插入        寫入40s:1000*100*2 讀取200次*2:10s      寫入40s:1500*100*2 讀取200次*2:50s

這下馬上顯示出Innodb在併發狀況下強勁的性能,幾乎沒有什麼性能衰減。而MyISAM單條插入速度變得很是慢,批量插入也降低了40%性能。

總結一下,在寫多讀少的應用中仍是Innodb插入性能更穩定,在併發狀況下也能基本,若是是對讀取速度要求比較快的應用仍是選MyISAM。

 

 

轉自於:http://blog.csdn.net/wjtlht928/article/details/46641865

相關文章
相關標籤/搜索