MySQL之儲存引擎InnoDB和MyISAM的區別及底層詳解

民工哥技術之路發表於2018-09-05

題外話:中華文化博大進深,從學Java到資料庫,無一不體現出同一元件魚和熊掌不可兼得的要義。自然,程式設計中安全和效率也很難同時做到完美,這一次InnoDB和MyISAM又讓我大開眼界。

好了,Talk is cheap,show you the code:

測試環境:Mysql 5.7.20-log,IDEA 2018

首先建立兩張表: testinnodb,testmyisam,sql如下:

Mysql之儲存引擎InnoDB和MyISAM的區別及底層詳解

1.同時大批量插入資料(百萬級,million),小編採用了儲存過程,程式碼及測試結果如下:

下面程式碼在IDEA上執行即可:

同時插入100W條資料,MyISAM耗時38s左右,而InnoDB卻耗時76分鐘4s左右,很明顯可以看出MyISAM在處理速度上完勝InnoDB,但是如果實際專案中使用,由於涉及到資料安全(或者事物安全)問題,大多數公司還是選擇了InnoDB, 較少公司使用MyISAM(得力於其在業務層的嚴格控制)。但MyISAM依然可以被我們使用在日誌資料分析,實驗等環境中。

2.再看其在刪改查方面的對比

改查耗時

刪除耗時

其實對比下來,差距並沒有插入資料那樣誇張,對於大多數要求事物安全的公司來說還是可以接受的。

PS: 你可以使用mysql外掛profile來顯示最近執行命令的持續時長,用法如下:

mysql預設是關閉profiles的,你需要開啟它,

檢視是否開啟命令: show variables like '%pro%';

小編已經把他開啟了,所以顯示為ON,預設為OFF。

開啟命令:set profiling=1;

關閉命令:set profiling=0;

查詢最近使用命令時長:show profiles;

根據Query ID查詢單個命令詳情: show profile for query 1;

根據Query ID查詢單個命令memory,source,cpu等詳情: show profile cpu for query 1;或者 show profile all for query 1;

測試Over,接下來總結一下:

1.InnoDB支援事物,外來鍵等高階的資料庫功能,MyISAM不支援。需要注意的是,InnDB行級鎖也不是絕對的,例如mysql執行一個未定範圍的sql時,也還是會鎖表,例如sql中like的使用

2.效率,明顯MyISAM在插入資料的表現是InnoDB所遠遠不及的,在刪改查,隨著InnoDB的優化,差距漸漸變小

3.行數查詢,InnoDB不儲存行數,也就是select的時候,要掃描全表,MyISAM只需讀取儲存的行數即可,這也是MyISAM查詢速度快的一個因素。

4.索引,InnoDB會自動建立Auto_Increment型別欄位的索引,一般習慣應用於主鍵,即主鍵索引(只包含該欄位),而MyISAM可以和其他欄位建立聯合索引。

除此之外,MyISAM還支援全文索引(FULLTEXT_INDEX),壓縮索引,InnoDB不支援。

備註:MyISAM的索引和資料是分開的,並且索引是有壓縮的,記憶體使用率就對應提高了不少。能載入更多索引,而Innodb是索引和資料是緊密捆綁的,沒有使用壓縮從而會造成Innodb比MyISAM體積龐大不小。

InnoDB儲存引擎被完全與MySQL伺服器整合,InnoDB儲存引擎為在主記憶體中快取資料和索引而維持它自己的緩衝池。InnoDB儲存它的表&索引在一個表空間中,表空間可以包含數個檔案(或原始磁碟分割槽)。這與MyISAM表不同,比如在MyISAM表中每個表被存在分離的檔案中。InnoDB 表可以是任何尺寸,即使在檔案尺寸被限制為2GB的作業系統上。

5.伺服器資料備份。InnoDB必須匯出SQL來備份,LOAD TABLE FROM MASTER操作對InnoDB是不起作用的,解決方法是首先把InnoDB表改成MyISAM表,匯入資料後再改成InnoDB表,但是對於使用的額外的InnoDB特性(例如外來鍵)的表不適用。

備註:而且MyISAM應對錯誤編碼導致的資料恢復速度快。MyISAM的資料是以檔案的形式儲存,所以在跨平臺的資料轉移中會很方便。在備份和恢復時可單獨針對某個表進行操作。

InnoDB是拷貝資料檔案、備份 binlog,或者用 mysqldump,支援災難恢復(僅需幾分鐘),MyISAM不支援,遇到資料崩潰,基本上很難恢復,所以要經常進行資料備份。

6.鎖的支援。**MyISAM只支援表鎖。InnoDB支援表鎖、行鎖 行鎖大幅度提高了多使用者併發操作的新能。但是InnoDB的行鎖,只是在WHERE的主鍵是有效的,非主鍵的WHERE都會鎖全表的

使用場景建議:

1)可靠性高或者要求事務處理,則使用InnoDB。這個是必須的。

2)表更新和查詢都相當的頻繁,並且表鎖定的機會比較大的情況指定InnoDB資料引擎的建立。

對比之下,MyISAM的使用場景:

1)做很多count的計算的。如一些日誌,調查的業務表。

2)插入修改不頻繁,查詢非常頻繁的。

MySQL能夠允許你在表這一層應用資料庫引擎,所以你可以只對需要事務處理的表格來進行效能優化,而把不需要事務處理的表格交給更加輕便的MyISAM引擎。對於 MySQL而言,靈活性才是關鍵。

引擎原理分析

MyISAM索引結構: MyISAM索引用的B+ tree來儲存資料,MyISAM索引的指標指向的是鍵值的地址,地址儲存的是資料。B+Tree的資料域儲存的內容為實際資料的地址,也就是說它的索引和實際的資料是分開的,只不過是用索引指向了實際的資料,這種索引就是所謂的非聚集索引

主索引如下:

輔助索引如下:

因此,過程為: MyISAM中索引檢索的演算法為首先按照B+Tree搜尋演算法搜尋索引,如果指定的Key存在,則取出其data域的值,然後以data域的值為地址,根據data域的值去讀取相應資料記錄。

InnoDB引擎的索引結構:

也是B+Treee索引結構。Innodb的索引檔案本身就是資料檔案,即B+Tree的資料域儲存的就是實際的資料,這種索引就是聚集索引。這個索引的key就是資料表的主鍵,因此InnoDB表資料檔案本身就是主索引。

InnoDB的輔助索引資料域儲存的也是相應記錄主鍵的值而不是地址,所以當以輔助索引查詢時,會先根據輔助索引找到主鍵,再根據主鍵索引找到實際的資料。所以Innodb不建議使用過長的主鍵,否則會使輔助索引變得過大。

建議使用自增的欄位作為主鍵,這樣B+Tree的每一個結點都會被順序的填滿,而不會頻繁的分裂調整,會有效的提升插入資料的效率。

主索引如下:

輔助索引如下:

上圖,可以看到葉節點包含了完整的資料記錄。這種索引叫做聚集索引。因為InnoDB的資料檔案本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統會自動選擇一個可以唯一標識資料記錄的列作為主鍵,如果不存在這種列,則MySQL自動為InnoDB表生成一個隱含欄位作為主鍵,這個欄位長度為6個位元組,型別為長整形。

而且,與MyISAM索引的不同是InnoDB的輔助索引data域儲存相應記錄主鍵的值而不是地址。換句話說,InnoDB的所有輔助索引都引用主鍵作為data域。

因此,過程為:將主鍵組織到一棵B+樹中,而行資料就儲存在葉子節點上,若使用”where id = 13”這樣的條件查詢主鍵,則按照B+樹的檢索演算法即可查詢到對應的葉節點,之後獲得行資料。若對Name列進行條件搜尋,則需要兩個步驟:第一步在輔助索引B+樹中檢索Name,到達其葉子節點獲取對應的主鍵。第二步使用主鍵在主索引B+樹種再執行一次B+樹檢索操作,最終到達葉子節點即可獲取整行資料。

兩種索引資料查詢過程如下:

MySQL之儲存引擎InnoDB和MyISAM的區別及底層詳解

相關文章