MySql 三大知識點——索引、鎖、事務,詳解

做者:莫那魯道java

來源:http://thinkinjava.cn/2019/03/16/2019-03-16-mysqlmysql

1.索引面試

索引,相似書籍的目錄,能夠根據目錄的某個頁碼當即找到對應的內容。算法

索引的優勢:1. 天生排序,2. 快速查找。sql

索引的缺點:1. 佔用空間,2. 下降更新表的速度。數據庫

注意點:小表使用全表掃描更快,中大表才使用索引。超級大表索引基本無效。併發

索引從實現上說,分紅 2 種:彙集索引和輔助索引(也叫二級索引或者非彙集索引)異步

從功能上說,分爲 6 種:普通索引,惟一索引,主鍵索引,複合索引,外鍵索引,全文索引。分佈式

詳細說說 6 種索引:性能

一、普通索引:最基本的索引,沒有任何約束。 二、惟一索引:與普通索引相似,但具備惟一性約束。 三、主鍵索引:特殊的惟一索引,不容許有空值。 四、複合索引:將多個列組合在一塊兒建立索引,能夠覆蓋多個列。 五、外鍵索引:只有InnoDB類型的表纔可使用外鍵索引,保證數據的一致性、完整性和實現級聯操做。 六、全文索引:MySQL 自帶的全文索引只能用於 InnoDB、MyISAM ,而且只能對英文進行全文檢索,通常使用全文索引引擎(ES,Solr)。

注意:主鍵就是惟一索引,可是惟一索引不必定是主鍵,惟一索引能夠爲空,可是空值只能有一個,主鍵不能爲空。

另外,InnoDB 經過主鍵聚簇數據,若是沒有定義主鍵且沒有定義彙集索引, MySql 會選擇一個惟一的非空索引代替,若是沒有這樣的索引,會隱式定義個 6 字節的主鍵做爲聚簇索引,用戶不能查看或訪問。

簡單點說:

一、設置主鍵時,會自動生成一個惟一索引,若是以前沒有彙集索引,那麼主鍵就是彙集索引。 二、沒有設置主鍵時,會選擇一個不爲空的惟一索引做爲彙集索引,若是尚未,那就生成一個隱式的 6 字節的索引。

MySql 將數據按照頁來存儲,默認一頁爲 16kb,當你在查詢時,不會只加載某一條數據,而是將這個數據所在的頁都加載到 pageCache 中,這個其實和 OS 的就近訪問原理相似。

MySql 的索引使用 B+ 樹結構。在說 B+ 樹以前,先說說 B 樹,B 樹是一個多路平衡查找樹,相較於普通的二叉樹,不會發生極度不平衡的情況,同時也是多路的。

B 樹的特色是:他會將數據也保存在非頁子節點。

看圖可知:

而這個特色會致使非頁子節點不能存儲大量的索引。

而 B+ Tree 就是針對這個對 B tree 作了優化。以下圖所示:

咱們看到,B+ Tree 將全部的 data 數據都保存到了葉子節點中,非也子節點只保存索引和指針。

咱們假設一個非頁子節點是 16kb,每一個索引,即主鍵是 bigint,即 8b,指針爲 8b。那麼每頁能存儲大約 1000 個索引(16kb/ 8b + 8b).

而一顆 3 層的 B+樹可以存儲多少索引呢?

以下圖:

大約可以存儲 10 億個索引。一般 B+ 樹的高度在 2-4 層,因爲 MySql 在運行時,根節點是常駐內存的,所以每次查找只須要大約 2 -3 次 IO。能夠說,B+ 樹的設計,就是根據機械磁盤的特性來進行設計的。

知道了索引的設計,咱們可以知道另一些信息:

一、MySql 的主鍵不能太大,若是使用 UUID 這種,將會浪費 B+ 樹的非葉子節點。 二、MySql 的主鍵最好是自增的,若是使用 UUID 這種,每次插入都會調整 B+樹,從而致使頁分裂,嚴重影響性能。

那麼,若是項目中使用了分庫分表,咱們一般都會須要一個主鍵進行 sharding,那怎麼辦呢?在實現上,咱們能夠保留自增主鍵,而邏輯主鍵用來做爲惟一索引便可。

2.鎖機制

關於 Mysql 的鎖,各類概念就會噴涌而出,事實上,鎖有好幾種維度,咱們來解釋一下。

1.類型維度

共享鎖(讀鎖 / S 鎖) 排它鎖(寫鎖 / X 鎖)

類型細分:

  • 意向共享鎖

  • 意向排他(互斥)鎖

悲觀鎖(使用鎖,即 for update)

樂觀鎖(使用版本號字段,相似 CAS 機制,即用戶本身控制。缺點:併發很高的時候,多了不少無用的重試)

2.鎖的粒度(粒度維度)

表鎖 頁鎖(Mysql BerkeleyDB 引擎) 行鎖(InnoDB)

3.鎖的算法(算法維度)

Record Lock(單行記錄) Gap Lock(間隙鎖,鎖定一個範圍,但不包含鎖定記錄) Next-Key Lock(Record Lock + Gap Lock,鎖定一個範圍,而且鎖定記錄自己, MySql 防止幻讀,就是使用此鎖實現)

4.默認的讀操做,上鎖嗎?

默認是 MVCC 機制(「一致性非鎖定讀」)保證 RR 級別的隔離正確性,是不上鎖的。

能夠選擇手動上鎖:select xxxx for update (排他鎖); 

select xxxx lock in share mode(共享鎖),稱之爲「一致性鎖定讀」。

使用鎖以後,就能在 RR 級別下,避免幻讀。固然,默認的 MVCC 讀,也能避免幻讀。

既然 RR 可以防止幻讀,那麼,SERIALIZABLE 有啥用呢?

防止丟失更新。例以下圖:

這個時候,咱們必須使用 SERIALIZABLE 級別進行串行讀取。

最後,行鎖的實現原理就是鎖住彙集索引,若是你查詢的時候,沒有正確地擊中索引,MySql 優化器將會拋棄行鎖,使用表鎖。

3.事務

事務是數據庫永恆不變的話題, ACID:原子性,一致性,隔離性,持久性

四個特性,最重要的就是一致性。而一致性由原子性,隔離性,持久性來保證。

原子性由 Undo log 保證。Undo Log 會保存每次變動以前的記錄,從而在發生錯誤時進行回滾。隔離性由 MVCC 和 Lock 保證。這個後面說。持久性由 Redo Log 保證。每次真正修改數據以前,都會將記錄寫到 Redo Log 中,只有 Redo Log 寫入成功,纔會真正的寫入到 B+ 樹中,若是提交以前斷電,就能夠經過 Redo Log 恢復記錄。

而後再說隔離性。

隔離級別:

一、未提交讀(RU)

二、已提交讀(RC)

三、可重複讀(RR)

四、串行化(serializable)

每一個級別都會解決不一樣的問題,一般是3 個問題:髒讀,不可重複讀,幻讀。一張經典的圖:

這裏有個注意點,關於幻讀,在數據庫規範裏,RR 級別會致使幻讀,可是,因爲 Mysql 的優化,MySql 的 RR 級別不會致使幻讀:在使用默認的 select 時,MySql 使用 MVCC 機制保證不會幻讀;

你也可使用鎖,在使用鎖時,例如 for update(X 鎖),lock in share mode(S 鎖),MySql 會使用 Next-Key Lock 來保證不會發生幻讀。前者稱爲快照讀,後者稱爲當前讀。

原理剖析:

一、RU 發生髒讀的緣由:RU 原理是對每一個更新語句的行記錄進行加鎖,而不是對整個事務進行加鎖,因此會發生髒讀。而 RC 和 RR 會對整個事務加鎖。 二、RC 不能重複讀的緣由:RC 每次執行 SQL 語句都會生成一個新的 Read View,每次讀到的都是不一樣的。而 RR 的事務從始至終都是使用同一個 Read View。 三、RR 不會發生幻讀的緣由: 上面說過了。

那 RR 和 Serializble 有什麼區別呢?答:丟失更新。本文關於鎖的部分已經提到。

MVCC 介紹:全稱多版本併發控制。

innoDB 每一個彙集索引都有 4 個隱藏字段,分別是主鍵(RowID),最近更改的事務 ID(MVCC 核心),Undo Log 的指針(隔離核心),索引刪除標記(當刪除時,不會當即刪除,而是打標記,而後異步刪除);

本質上,MVCC 就是用 Undo Log 鏈表實現。

MVCC 的實現方式:事務以排它鎖的方式修改原始數據,把修改前的數據存放於 Undo Log,經過回滾指針與數據關聯,若是修改爲功,什麼都不作,若是修改失敗,則恢復 Undo Log 中的數據。

多說一句,一般咱們認爲 MVCC 是相似樂觀鎖的方式,即便用版本號,而實際上,innoDB 不是這麼實現的。固然,這不影響咱們使用 MySql。

更多技術乾貨

 

近期100多篇技術乾貨,升職加薪必看

百度、騰訊、阿里、谷歌 面試題視頻詳解合集

深刻 Redis 主從複製的原理詳解

ZooKeeper 一致性協議 ZAB 原理

Google 出品的 Java 編碼規範,權威又科學

46張PPT講述JVM、GC算法和性能調優

基於 Zookeeper 的分佈式鎖實現

30 道 Dubbo 面試題及答案

RDB 和 AOF 持久化的原理是什麼?

相關文章
相關標籤/搜索