mysql存儲引擎
如何選擇mysql存儲引擎
先得了解下各個存儲引擎區別
功能 | MylSAM | MEMORY | InnoDB | Archive |
---|---|---|---|---|
功能 | MylSAM | MEMORY | InnoDB | Archive |
存儲限制 | 256TB | RAM | 64TB | None |
支持事務 | No | No | Yes | No |
支持全文索引 | Yes | No | No | No |
支持樹索引 | Yes | Yes | Yes | No |
支持哈希索引 | No | Yes | No | No |
支持數據緩存 | No | N/A | Yes | No |
支持外鍵 | No | No | Yes | No |
可以根據以下的原則來選擇 MySQL 存儲引擎:
- 如果要提供提交、回滾和恢復的事務安全(ACID 兼容)能力,並要求實現併發控制,InnoDB 是一個很好的選擇。
- 如果數據表主要用來插入和查詢記錄,則 MyISAM 引擎提供較高的處理效率。
- 如果只是臨時存放數據,數據量不大,並且不需要較高的數據安全性,可以選擇將數據保存在內存的 MEMORY 引擎中,MySQL 中使用該引擎作爲臨時表,存放查詢的中間結果。
- 如果只有 INSERT 和 SELECT 操作,可以選擇Archive 引擎,Archive 存儲引擎支持高併發的插入操作,但是本身並不是事務安全的。Archive 存儲引擎非常適合存儲歸檔數據,如記錄日誌信息可以使用 Archive 引擎。
提示:使用哪一種引擎要根據需要靈活選擇,一個數據庫中多個表可以使用不同的引擎以滿足各種性能和實際需求。使用合適的存儲引擎將會提高整個數據庫的性能。
詳細說一下innodb與MyISAM的區別
MyISAM和InnoDB的區別:
- InnoDB支持事務,MyISAM不支持。對於InnoDB每一條SQL語言都默認封裝成事務,自動提交,這樣會影響速度,所以最好把多條SQL語言放在begin和commit之間,組成一個事務;
- InnoDB支持外鍵,而MyISAM不支持。
- InnoDB是聚集索引,使用B+Tree作爲索引結構,數據文件是和(主鍵)索引綁在一起的(表數據文件本身就是按B+Tree組織的一個索引結構),必須要有主鍵,通過主鍵索引效率很高。MyISAM是非聚集索引,也是使用B+Tree作爲索引結構,索引和數據文件是分離的,索引保存的是數據文件的指針。主鍵索引和輔助索引是獨立的。
- InnoDB不保存表的具體行數,執行select count(*) from table時需要全表掃描。而MyISAM用一個變量保存了整個表的行數,執行上述語句時只需要讀出該變量即可,速度很快。
- Innodb不支持全文索引,而MyISAM支持全文索引,查詢效率上MyISAM要高;5.7以後的InnoDB支持全文索引了。
- InnoDB支持表、行級鎖(默認),而MyISAM支持表級鎖。
- InnoDB表必須有主鍵(用戶沒有指定的話會自己找或生產一個主鍵),而Myisam可以沒有。
- Innodb存儲文件有frm、ibd,而Myisam是frm、MYD、MYI。 Innodb:frm是表定義文件,ibd是數據文件。 Myisam:frm是表定義文件,myd是數據文件,myi是索引文件。
索引
什麼是索引
索引其實是一種數據結構,能夠幫助我們快速的檢索數據庫中的數據。
有哪幾種索引
按照功能劃分
- 普通索引:最基本的索引,沒有任何約束。
- 唯一索引:與普通索引類似,但具有唯一性約束。
- 主鍵索引:特殊的唯一索引,不允許有空值。
- 複合索引:將多個列組合在一起創建索引,可以覆蓋多個列。
- 外鍵索引:只有InnoDB類型的表纔可以使用外鍵索引,保證數據的一致性、完整性和實現級聯操作。
- 全文索引:MySQL 自帶的全文索引只能用於 InnoDB、MyISAM ,並且只能對英文進行全文檢索,一般使用全文索引引擎(ES,Solr)。
按照結構劃分
- Hash索引
- B+ Tree索引
我們常用的innodb默認是B+索引
爲什麼採用B+ 樹嗎?
B+樹是爲磁盤及其他存儲輔助設備而設計一種平衡查找樹(不是二叉樹)。B+樹中,所有記錄的節點按大小順序存放在同一層的葉節點中,各葉節點用指針進行連接。
數據庫中B+樹索引分爲聚集索引(clustered index)和非聚集索引(secondary index).這兩種索引的共同點是內部都是B+樹,高度都是平衡的,葉節點存放着所有數據。不同點是葉節點是否存放着一整行數據。
B+樹有如下特點:
- B+樹每個節點可以包含更多的節點,這樣做有兩個原因,一個是降低樹的高度。另外一個是將數據範圍變爲多個區間,區間越多,數據檢索越快。
- 每個節點不再只是存儲一個key了,可以存儲多個key。
- 非葉子節點存儲key,葉子節點存儲key和數據。
- 葉子節點兩兩指針相互鏈接,順序查詢性能更高。
通俗的講
- B+樹的非葉子節點只是存儲key,佔用空間非常小,因此每一層的節點能索引到的數據範圍更加的廣。換句話說,每次IO操作可以搜索更多的數據。
- 葉子節點兩兩相連,符合磁盤的預讀特性。比如葉子節點存儲50和55,它有個指針指向了60和62這個葉子節點,那麼當我們從磁盤讀取50和55對應的數據的時候,由於磁盤的預讀特性,會順便把60和62對應的數據讀取出來。這個時候屬於順序讀取,而不是磁盤尋道了,加快了速度。
- 支持範圍查詢,而且部分範圍查詢非常高效,每個節點能索引的範圍更大更精確,也意味着 B+樹單次磁盤IO的信息量大於B-樹,I/O效率更高。
B+樹和Hash索引比較起來有什麼優缺點嗎?
-
Hash索引僅僅能滿足"=","IN"和""查詢,不能使用範圍查詢,因爲經過相應的Hash算法處理之後的Hash值的大小關係,並不能保證和Hash運算前完全一樣;
-
Hash索引無法被用來避免數據的排序操作,因爲Hash值的大小關係並不一定和Hash運算前的鍵值完全一樣;
-
Hash索引不能利用部分索引鍵查詢,對於組合索引,Hash索引在計算Hash值的時候是組合索引鍵合併後再一起計算Hash值,而不是單獨計算Hash值,所以通過組合索引的前面一個或幾個索引鍵進行查詢的時候,Hash索引也無法被利用;
-
Hash索引在任何時候都不能避免表掃描,由於不同索引鍵存在相同Hash值,所以即使取滿足某個Hash鍵值的數據的記錄條數,也無法從Hash索引中直接完成查詢,還是要回表查詢數據;
-
Hash索引遇到大量Hash值相等的情況後性能並不一定就會比B+樹索引高。 如果是等值查詢,那麼哈希索引明顯有絕對優勢,因爲只需要經過一次算法即可找到相應的鍵值;當然了,這個前提是,鍵值都是唯一的。如果鍵值不是唯一的,就需要先找到該鍵所在位置,然後再根據鏈表往後掃描,直到找到相應的數據;
-
如果是範圍查詢檢索,這時候哈希索引就毫無用武之地了,因爲原先是有序的鍵值,經過哈希算法後,有可能變成不連續的了,就沒辦法再利用索引完成範圍查詢檢索;
-
同理,哈希索引沒辦法利用索引完成排序,以及like ‘xxx%’ 這樣的部分模糊查詢(這種部分模糊查詢,其實本質上也是範圍查詢);
-
哈希索引也不支持多列聯合索引的最左匹配規則;
-
B+樹索引的關鍵字檢索效率比較平均,不像B樹那樣波動幅度大,在有大量重複鍵值情況下,哈希索引的效率也是極低的,因爲存在所謂的哈希碰撞問題。
-
在大多數場景下,都會有範圍查詢、排序、分組等查詢特徵,用B+樹索引就可以了。
爲什麼主鍵推薦自增長
因爲使用自增 id 可以避免頁分裂
什麼是頁分裂
mysql (注意本文講的 mysql 默認爲InnoDB 引擎)底層數據結構是 B+ 樹,所謂的索引其實就是一顆 B+ 樹,一個表有多少個索引就會有多少顆 B+ 樹,mysql 中的數據都是按順序保存在 B+ 樹上的(所以說索引本身是有序的)。 然後 mysql 在底層又是以數據頁爲單位來存儲數據的,一個數據頁大小默認爲 16k,當然你也可以自定義大小,也就是說如果一個數據頁存滿了,mysql 就會去申請一個新的數據頁來存儲數據。 如果主鍵爲自增 id 的話,mysql 在寫滿一個數據頁的時候,直接申請另一個新數據頁接着寫就可以了。
如果主鍵是非自增 id,爲了確保索引有序,mysql 就需要將每次插入的數據都放到合適的位置上。
當往一個快滿或已滿的數據頁中插入數據時,新插入的數據會將數據頁寫滿,mysql 就需要申請新的數據頁,並且把上個數據頁中的部分數據挪到新的數據頁上。
這就造成了頁分裂,這個大量移動數據的過程是會嚴重影響插入效率的。
其實對主鍵 id 還有一個小小的要求,在滿足業務需求的情況下,儘量使用佔空間更小的主鍵 id,因爲普通索引的葉子節點上保存的是主鍵 id 的值,如果主鍵 id 佔空間較大的話,那將會成倍增加 mysql 空間佔用大小。
mysql鎖瞭解嗎?
MySQL有哪幾種鎖,能說下嗎?
1. 類型維度
- 共享鎖(讀鎖 / S 鎖)
- 排它鎖(寫鎖 / X 鎖) 類型細分: 意向共享鎖 意向排他(互斥)鎖
- 悲觀鎖(使用鎖,即 for update)
- 樂觀鎖(使用版本號字段,類似 CAS 機制,即用戶自己控制。缺點:併發很高的時候,多了很多無用的重試)
2. 鎖的粒度(粒度維度)
-
表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的概率最高,併發度最低。
-
行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高。
-
頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度一般。
3. 鎖的算法(算法維度)
- Record Lock(單行記錄)
- Gap Lock(間隙鎖,鎖定一個範圍,但不包含鎖定記錄)
- Next-Key Lock(Record Lock + Gap Lock,鎖定一個範圍,並且鎖定記錄本身, MySql 防止幻讀,就是使用此鎖實現)
默認讀會上鎖嗎?
默認是 MVCC 機制(“一致性非鎖定讀”)保證 RR 級別的隔離正確性,是不上鎖的。 可以選擇手動上鎖:select xxxx for update (排他鎖); select xxxx lock in share mode(共享鎖),稱之爲“一致性鎖定讀”。
使用鎖之後,就能在 RR 級別下,避免幻讀。當然,默認的 MVCC 讀,也能避免幻讀。
高併發情況下鎖會帶來有哪些問題?
在高併發的情況下事務的併發處理會帶來幾個問題
- 髒讀:指在事務 A 處理過程裏讀取到了事務 B 未提交的事務中的數據。比如在轉賬的例子中:小 A 開了一個事務給小 B 轉了1000 塊,還沒提交事務的時候就跟小 B 說,錢已經到賬了。這個時候小 B 去看了一下餘額,發現果真到賬了(然後就開開心心刷抖音去了),這個時候小 A 回滾了事務,把 1000 塊又搞回去了。小 B 刷完抖音再去看下餘額,發現錢又不見了。
- 不可重複讀:指在一個事務執行的過程中多次查詢某一數據的時候結果不一致的現象,由於在執行的過程中被另一個事務修改了這個數據並提交了事務。比如:事務 A 第一次讀小明的年齡是 18 歲,此時事務 B 將小明的年齡改成了 20 並提交了,這個時候事務 A 再次讀取小明的年齡發現是 20,這就是同一條數據不可重複讀。
- 幻讀:幻讀通常指的是對一批數據的操作完成後,有其他事務又插入了滿足條件的數據導致的現象。比如:事務 A 將數據庫性別爲男的狀態都改成1 表示有錢人,這個時候事務 B 又插入了一條狀態爲 0 沒錢人的記錄,這個時候,用戶再查看剛剛修改的數據時就會發現還有一行沒有修改,這就出現了幻讀。幻讀往往針對 insert 操作,髒讀和不可重複讀針對 select 操作。
mysql是怎麼處理的
mysql針對上述問題增加了事務的隔離級別
- Read uncommitted (讀未提交):最低級別,任何情況都無法保證。
- Read committed (讀已提交):可避免髒讀的發生。
- Repeatable read (可重複讀):可避免髒讀、不可重複讀的發生。
- Serializable (串行化):可避免髒讀、不可重複讀、幻讀的發生。