高階工程師面試大全- 資料庫篇

最美岁月發表於2024-08-15

1.redis 相關面試題

1.1 Redis為什麼執行這麼快?

(1)純記憶體操作:Redis將所有資料儲存在記憶體中,這意味著對資料的讀寫操作直接在記憶體中執行,而記憶體的訪問速度遠遠高於磁碟。這種設計使得Redis能夠已接近硬體極限的速度處理資料讀寫
(2)單執行緒模型:Redis使用單執行緒模型來處理客戶端請求。這可能聽起來效率不高,但是實際上,這種設計避免了多執行緒頻繁切換和過度競爭帶來的效能開銷。Redis每個請求的執行時間都是很短的,因此單執行緒下,也能處理大量的併發請求
(3)I/O多路複用:Redis使用了I/O多路複用技術,可以在單執行緒的環境下同時監聽多個客戶端連線,只有當有網路事件(如使用者傳送一個請求)發生的時候才會進行實際的I/O操作。這樣有效的利用了CPU資源,減少了無謂的等待
(4)高效資料結構:Redis提供了多種高效的資料結構,如雜湊表、有序集合等。這些資料結構的實現都經過了最佳化,使得Redis在處理這些資料結構的操作是非常高效的

1.2 Redis是單執行緒執行還是多執行緒執行?它有執行緒安全問題嗎?為什麼嗎?

Redis版本在6.0之前都是使用的單執行緒執行的。所有的客戶端的請求處理、命令執行以及資料讀寫操作都是在一個主執行緒中完成得。這種設計目的就是為了防止多執行緒環境下的鎖競爭和上下文切換所帶來的效能開銷,這樣保證在高併發場景下的效能

Redis版本在6.0中,開始引入了多執行緒的支援,但是這僅限於網路I/O層面,即在網路請求階段使用工作執行緒進行處理,對於指令的執行過程,仍然是在主執行緒來處理,所以不會存在多個執行緒通知執行操作指令的情況

關於執行緒安全問題,從Redis服務層面倆看,Redis Server本身就是一個執行緒安全按的K-V資料庫,也就是說在Redis Server上面執行的指令,不需要任何同步機制,不會存線上程安全問題

1.3 在實際工作中,使用Redis實現了哪些業務場景?

Redis在實際工作中廣泛應用於多種業務場景,以下是一些常見的例子:

快取:Redis作為Key-Value形態的記憶體資料庫,最先會被想到的應用場景就是作為資料快取。Redis提供了鍵過期功能,也提供了鍵淘汰策略,所以Redis用在快取的場合非常多

排行榜:很多網站都有排行榜應用,如京東的月度銷量榜單、商品按時間上新排行榜等。Redis提供的有序集合(zset)資料類

分散式會話:在叢集模式下,一般會搭建以Redis等記憶體等記憶體資料庫為中心的session服務,session不再由容器管理,而是由session服務及記憶體資料庫管理

分散式鎖:在高併發的情景,可以利用Redis的setnx功能來編寫分散式鎖

1.4 Redis常用資料型別有哪些?

字串(String):最簡單的資料型別,可以包含任意資料,如文字、二進位制資料等。常見的使用場景是儲存Session資訊、儲存快取資訊、儲存整數資訊,可以使用incr實現整數+1,使用decr實現整數-1
列表(List):有序的字串元素集合,支援雙端進行插入和刪除操作,可以用作佇列或棧
雜湊(Hash):用於儲存物件,類似於關聯陣列。每個雜湊可以包含欄位和與之相關聯的值。常見使用場景是儲存Session資訊、儲存商品的購物車,購物車非常適用於雜湊字典表示,使用人員唯一編號作為字典的key,value值可以儲存商品的id和數量等資訊、儲存詳情頁等資訊
集合(Set):一個無序並唯一的鍵值集合。它常見的使用場景是是仙女關注功能,比如關注我的人和我關注的人,使用集合儲存,可以保證人員不重複
有序集合(Sorted Set):使用zset表示,相當於Set集合型別多了一個排序屬性score(分值)。。它常見的使用場景是可以用來儲存排名資訊,關注列表功能,這樣就可以根據關注實現排序展示

1.5 有序集合底層是如何實現的?

在Redis7之前,有序集合使用的是ziplist(壓縮列表)+skiplist(跳躍表),當資料列表元素小於128個,並且所有元素成員的長度都小於64位元組時,使用壓縮列表儲存,否則使用調錶儲存

在Redis之後,有序集合使用listPack(緊湊列表)+skiplist(跳躍表)

1.6 什麼是跳錶?為什麼使用跳錶?

skiplist是一種以空間換時間的資料結構。由於連結串列無法進行二分查詢,因此借鑑資料庫索引的思想,提取出連結串列中的關鍵姐點(索引),現在關鍵節點上查詢,在進入下層連結串列查詢提取多層關鍵節點,就形成了跳錶。但是由於索引要佔據一定的空間,所以索引新增的越多,佔用的空間越多。

對於一個單連結串列來講,即便連結串列中儲存的資料是有序的,如果我們要想在其中查詢某個資料,也只能從頭到尾遍歷連結串列。這樣查詢效率就會很低,時間複雜度會很高O(N)

從這個例子裡,我們看出,加來一層索引之後,查詢一個結點需要遍歷的結點個數減少了,也就是說查詢效率提高了。時間複雜度從原來的O(n)到O(logn),是一空間換時間的解決方法

1.7 使用Redis如何實現分散式鎖?

使用Redis實現分散式鎖可以透過setnx(set if not exists)命令實現,但當我們使用setnx建立鍵值成功時,則表中加鎖成功,否則程式碼加鎖失敗,實現示例如下:

127.0.0.1:6379> setnx lock true
(integer) 1#建立鎖成功
#邏輯業務處理..

當我們重複加鎖時,只有第一次會加鎖成功

127.8..1:6379> setnx lock true # 第一次加鎖
(integer) 1
127.8.8.1:6379> setnx lock true # 第二次加鎖
(integer) 0

從上述命令可以看出,我們可以看執行結果返回是不是1,就可以看出是否加鎖成功

釋放分散式鎖

127.0.0.1:6379> de1 lock
(integer) 1 #釋放鎖

然而,如果使用 setnx lock true 實現分散式鎖會存在死鎖問題,以為 setnx 如未設定過期時間,鎖忘記刪了或加鎖執行緒當機都會導致死鎖,也就是分散式鎖一直被佔用的情況

解決死鎖問題

死鎖問題可以透過設定超時時間來解決,如果超過了超時時間,分佈鎖會自動釋放,這樣就不會存在死鎖問題了也就是 setnx和 expire 配合使用,在 Redis 2.6.12 版本之後,新增了一個強大的功能,我們可以使用一個原子操作也就是一條命令來執行 setnx 和expire 操作了,實現示例如下:

其中ex為設定超時時間, nx 為元素非空判斷,用來判斷是否能正常使用鎖的。
因此,我們在 Redis 中實現分散式鎖最直接的方案就是使用 set key value ex timeout nx 的方式來實現。

1.8 Redis資料持久化方案?

Redis是一個記憶體資料庫,一旦斷電或伺服器程序退出,記憶體資料庫中的資料將全部丟失,所以需要Redis持久化

Redis持久化就是把資料儲存在磁碟上,利用永久性儲存介質將資料儲存,在特定的時間將儲存的資料進行恢復的工作機制

Redis提供兩種持久化機制:
RDB(Redis DataBase):儲存資料結果,關注點在資料(快照)

AOF(Append Only File):儲存操作過程,關注點在資料的操作過程(命令)

RDB與AOF觸發方式、優缺點:
RDB的觸發方式:

手動觸發:透過命令手動生成快照 (save,bgsave)

自動觸發:透過配置引數的設定觸發自動生成快照

缺點:

快照時間有間隔,不能實時備份,丟失資料可能會比較多

開啟子程序備份資料,在資料集比較龐大時,fork()可能會非常耗時,造成伺服器在一定時間內停止處理客戶端。

優點:

1.恢復資料比較快

2.備份的檔案就是原始記憶體資料的大小,不會額外增加資料佔用,

AOF的觸發方式

1.手動觸發

透過bgrewriteaof命令:重新AOF持久化生成aof檔案(觸發重寫)

2.自動觸發

預設情況,redis是沒有開啟AOF(預設使用RDB持久化),需要透過配置檔案開啟

AOF的優缺點

優點:

資料安全性高,不易丟資料

AOF檔案有序儲存了所有寫操作,可讀性強

缺點:

AOF方式生成檔案體積變大

資料恢復速度比RDB慢

1.9 Redis面試題-快取穿透,快取擊穿,快取雪崩

1 穿透: 兩邊都不存在(皇帝的新裝) (黑名單) (布隆過濾器)

2 擊穿:一個熱點的key失效了,這時大量的併發請求直接到達資料庫. (提前預熱)

3 雪崩:大量key同時失效 (避免大量的key同一時間失效,錯峰)

1.91 Redis 過期鍵刪除策略

1)惰性刪除:放任鍵過期不管,但是每次從鍵空間中獲取鍵時,都檢查取得的鍵是否過期,如果過期的話,就刪除該鍵;如果沒有過期,就返回該鍵。

2)定期刪除:每隔一段時間程式就對資料庫進行一次檢查,刪除裡面的過期鍵。至於要刪除多少過期鍵,以及要檢查多少個資料庫,則由演算法決定。

3)記憶體淘汰策略 Redis 記憶體資料集大小上升到一定大小的時候,就會施行資料淘汰策略。

1.92 Redis主從同步機制

步驟如下:(全量)

1.從伺服器向主伺服器傳送同步命令 sync;

2.主資料庫接收到同步命令後,會執行 bgsave 命令,在後臺生成一個 rdb 檔案,並使用一個緩衝區記錄從現在開始執行的所有寫命令;

3.當主伺服器執行完 bgsave 命令後,主伺服器會將 bgsave 命令生成的 rdb 檔案傳送給從伺服器;

4.從伺服器接收到這個 rdb 檔案,然後載入到記憶體 ;之後主伺服器會把剛剛在快取區的命令同步過來,從伺服器就會執行這些命名。(兩邊就一致了)

5.以上處理完之後,之後主資料庫每執行一個寫命令,都會將被執行的寫命令傳送給從資料庫。

1.93 Redis 和 Mysql 資料庫資料如何保持一致性

1、在發現快取沒有資料後,在執行查詢資料庫前,對該Key進行加鎖,查詢資料庫並放入快取後再解鎖,這樣可以避免快取擊穿問題,當某個redis資料不存在時,大量執行緒併發查詢資料庫。

2、在需要執行雙刪前,對該Key進行加鎖,之後執行刪除快取,更新資料庫,放入新資料到快取,在解鎖。保證快取和資料一致性。

3、加鎖的Key都需要設定過期時間,避免因為當機造成死鎖。

1.94 Redis叢集

Redis提供了多種叢集模式以適應不同場景下的高可用性和水平擴充套件需求。以下是Redis叢集模式:

主從複製(Master-Slave)模式:

在此模式下,有一個主節點負責處理寫入請求,而從節點則複製主節點的資料並提供讀取服務。

優點:實現簡單,能實現資料冗餘,透過讀寫分離提高系統效能。

缺點:需要手動進行故障轉移,無法自動處理主節點故障;不支援自動的資料分割槽(sharding),難以做到水平擴充套件。

哨兵(Sentinel)模式:

Sentinel是Redis提供的一個高可用性解決方案,它能監控主從節點狀態,並在主節點出現故障時自動完成故障轉移。

優點:解決了主從模式下手動故障轉移的問題,提供了自動化監控和故障恢復機制。

缺點:雖然比主從模式增加了自動化,但仍不支援自動的資料分割槽,且隨著節點數量增加,管理和配置的複雜性也會增大。

Redis Cluster模式:

Redis Cluster是官方正式支援的分散式解決方案,它採用了資料分片(sharding)技術,將資料分散在多個節點上。

優點:真正實現了分散式儲存,每個節點都可以處理讀寫請求,具備良好的水平擴充套件能力;內建了資料自動分割、故障檢測與轉移功能。

缺點:相比其他模式更復雜,需要更多的網路資源和配置管理;客戶端需要支援叢集特性;跨slot的資料操作可能涉及多個節點,有一定複雜度。

1.95 redis的資料是如何儲存的以及儲存的資料結構

儲存結構

字典(dict)實現

redis 資料庫透過 dict 實現對映關係。key 的固定型別是 string,value 的型別有多種。

redis 中 KV 組織是透過字典來實現的;hash 結構當節點超過512 個或者單個字串長度大於 64 時,hash 結構採用字典實現

dict 由雜湊表 dictht + 雜湊節點 dictEntry 組成。雜湊表有兩個,通常 ht[0] 使用,ht[1] 不使用;rehash 時,ht[0] 儲存 rehash 之前的資料,ht[1] 儲存新資料和 ht[0] 遷移來的資料。

1)字串經過 hash 函式運算得到 64 位整數;

2)相同字串多次透過 hash 函式得到相同的64位整數;

3)整數對 取餘可以轉化為位運算;sizemask是size-1,屬於對字典的最佳化。因為雜湊表的儲存是透過hash(key)%size=index確定索引,sizemask是對取餘長度的最佳化,將hash(key)%size變成hash(key) &sizemask,把除法最佳化為二進位制的運算,從而提高執行速度,這種最佳化的前提是 陣列的長度必須是2的n次冪(2 n 2^n2n)。

雜湊衝突

雜湊衝突指的是不同的鍵在雜湊表中計算得到相同的雜湊值,但它們的實際存放位置並不相同。在雜湊表中,每個鍵透過雜湊函式對映到一個桶(bucket)或槽(slot),儲存在對應的位置上。

由於雜湊表的大小是有限的,而鍵的數量可能是無限的,所以雜湊衝突是不可避免的。

我們透過負載因子 LoadFactor = used / size 來衡量雜湊衝突的程度, used 是陣列儲存元素的個數,size 是陣列的長度;
負載因子越小,衝突越小;負載因子越大,衝突越大;redis 的負載因子是 1 .

擴容

  • 如果負載因子 > 1 ,則會發生擴容;擴容的規則是翻倍;
  • 如果正在 fork (在 rdb、aof 複寫以及 rdb-aof 混用情況下)時,會阻止擴容;
  • 但是此時若負載因子 > 5 ,索引效率大大降低, 則馬上擴容;這裡涉及到寫時複製原理;

在寫時複製中,當需要修改一個資料副本時,不會立即進行實際的複製操作,而是在修改發生時建立該資料的新副本。這樣可以避免對原始資料進行修改,從而保持資料的一致性和完整性。
寫時複製核心思想:只有在不得不復制資料內容時才去複製資料內容;

縮容

如果負載因子 < 0.1 ,則會發生縮容;縮容的規則是恰好包含used 的 2 n 2^n2n

恰好的理解:假如此時陣列儲存元素個數為 9,恰好包含該元素的就是 ,也就是 16;

為什麼縮容的負載因子不是小於1?
因為縮容的負載因子是小於1的話會造成頻繁的擴縮容,擴縮容都有分配記憶體的操作,記憶體操作變得頻繁就會造成IO密集。

漸進式rehash

擴容和縮容都會導致rehash,因為對映演算法發生了改變。
當 hashtable 中的元素過多的時候,因為redis是一個資料庫,裡面儲存的資料非常多,不能一次性 rehash 到ht[1];這樣會長期佔用 redis,其他命令得不到響應;所以需要使用漸進式 rehash。

rehash步驟:
將 ht[0] 中的元素重新經過 hash 函式生成 64 位整數,再對ht[1] 長度進行取餘,從而對映到 ht[1]。

漸進式規則:
1) 分治的思想,將 rehash 分到之後的每步增刪改查的操作當中。
2)在定時器中,最大執行一毫秒 rehash ;每次步長 100 個陣列槽位。
3)處理漸進式 rehash 的過程中,不會發生擴容和縮容。

2. mysql相關面試題

2.1 什麼是資料庫事務?

資料庫事務是一個作為單個邏輯工作單元執行的一系列操作。事務具有ACID屬性,即原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和永續性(Durability)。這意味著事務內的操作要麼全部成功,要麼全部失敗,保持資料完整性,並且獨立於其他事務執行。

2.2 MySQL中InnoDB與MyISAM的區別是什麼?

InnoDB支援事務處理,行級鎖定和外來鍵,適用於需要高併發和事務處理的場景。MyISAM不支援事務和行級鎖定,但讀取速度快,適用於查詢密集型的場景。

2.3 如何最佳化MySQL查詢?

最佳化MySQL查詢的方法包括:使用合適的索引、避免在WHERE子句中使用函式、選擇合適的資料型別、使用LIMIT語句減少資料量、避免全表掃描、合理設計表結構等。

2.4 為什麼選擇 B+ 樹

  • 雜湊索引雖然能提供O(1)複雜度查詢,但對範圍查詢和排序卻無法很好的支援,最終會導致全表掃描。
  • B 樹能夠在非葉子節點儲存資料,但會導致在查詢連續資料可能帶來更多的隨機 IO。
  • 而 B+ 樹的所有葉節點可以透過指標來相互連線,減少順序遍歷帶來的隨機 IO。

2.5 什麼是覆蓋索引和索引下推?

覆蓋索引:

在某個查詢裡面,索引 k 已經“覆蓋了”我們的查詢需求,稱為覆蓋索引。
覆蓋索引可以減少樹的搜尋次數,顯著提升查詢效能,所以使用覆蓋索引是一個常用的效能最佳化手段。
索引下推:

MySQL 5.6 引入的索引下推最佳化(index condition pushdown), 可以在索引遍歷過程中,對索引中包含的欄位先做判斷,直接過濾掉不滿足條件的記錄,減少回表次數。

2.6 哪些操作會導致索引失效?

對索引使用左或者左右模糊匹配,也就是 like %xx 或者 like %xx% 這兩種方式都會造成索引失效。原因在於查詢的結果可能是多個,不知道從哪個索引值開始比較,於是就只能透過全表掃描的方式來查詢。
對索引進行函式/對索引進行表示式計算,因為索引保持的是索引欄位的原始值,而不是經過函式計算的值,自然就沒辦法走索引。
對索引進行隱式轉換相當於使用了新函式。
WHERE 子句中的 OR語句,只要有條件列不是索引列,就會進行全表掃描。

2.7 MySQL 的 redo log 和 binlog 區別?

2.8 為什麼 redo log 具有 crash-safe 的能力,是 binlog 無法替代的?

第一點:redo log 可確保 innoDB 判斷哪些資料已經刷盤,哪些資料還沒有

redo log 和 binlog 有一個很大的區別就是,一個是迴圈寫,一個是追加寫。也就是說 redo log 只會記錄未刷盤的日誌,已經刷入磁碟的資料都會從 redo log 這個有限大小的日誌檔案裡刪除。binlog 是追加日誌,儲存的是全量的日誌。
當資料庫 crash 後,想要恢復未刷盤但已經寫入 redo log 和 binlog 的資料到記憶體時,binlog 是無法恢復的。雖然 binlog 擁有全量的日誌,但沒有一個標誌讓 innoDB 判斷哪些資料已經刷盤,哪些資料還沒有。
但 redo log 不一樣,只要刷入磁碟的資料,都會從 redo log 中抹掉,因為是迴圈寫!資料庫重啟後,直接把 redo log 中的資料都恢復至記憶體就可以了。
第二點:如果 redo log 寫入失敗,說明此次操作失敗,事務也不可能提交

redo log 每次更新操作完成後,就一定會寫入日誌,如果寫入失敗,說明此次操作失敗,事務也不可能提交。
redo log 內部結構是基於頁的,記錄了這個頁的欄位值變化,只要crash後讀取redo log進行重放,就可以恢復資料。
這就是為什麼 redo log 具有 crash-safe 的能力,而 binlog 不具備。


2.9 當資料庫 crash 後,如何恢復未刷盤的資料到記憶體中?

根據 redo log 和 binlog 的兩階段提交,未持久化的資料分為幾種情況:

change buffer 寫入,redo log 雖然做了 fsync 但未 commit,binlog 未 fsync 到磁碟,這部分資料丟失。
change buffer 寫入,redo log fsync 未 commit,binlog 已經 fsync 到磁碟,先從 binlog 恢復 redo log,再從 redo log 恢復 change buffer。
change buffer 寫入,redo log 和 binlog 都已經 fsync,直接從 redo log 裡恢復。

2.91 什麼是兩階段提交?

MySQL 將 redo log 的寫入拆成了兩個步驟:prepare 和 commit,中間再穿插寫入binlog,這就是"兩階段提交"。

而兩階段提交就是讓這兩個狀態保持邏輯上的一致。redolog 用於恢復主機故障時的未更新的物理資料,binlog 用於備份操作。兩者本身就是兩個獨立的個體,要想保持一致,就必須使用分散式事務的解決方案來處理。

為什麼需要兩階段提交呢?

如果不用兩階段提交的話,可能會出現這樣情況
先寫 redo log,crash 後 bin log 備份恢復時少了一次更新,與當前資料不一致。
先寫 bin log,crash 後,由於 redo log 沒寫入,事務無效,所以後續 bin log 備份恢復時,資料不一致。
兩階段提交就是為了保證 redo log 和 binlog 資料的安全一致性。只有在這兩個日誌檔案邏輯上高度一致了才能放心的使用。
在恢復資料時,redolog 狀態為 commit 則說明 binlog 也成功,直接恢復資料;如果 redolog 是 prepare,則需要查詢對應的 binlog事務是否成功,決定是回滾還是執行。

2.92 CHAR和VARCHAR的區別?

  1. CHAR和VARCHAR型別在儲存和檢索方面有所不同
  2. CHAR列長度固定為建立表時宣告的長度,長度值範圍是1到255
  3. 當CHAR值被儲存時,它們被用空格填充到特定長度,檢索CHAR值時需刪除尾隨空格

2.93 聚簇索引與非聚簇索引區別

儲存方式不同:#

聚簇索引是將資料按照索引順序儲存在磁碟上,因此聚簇索引的資料儲存和索引儲存是混合在一起的;而非聚簇索引則是將索引和資料分開儲存的。

唯一性不同:#

聚簇索引必須是唯一的,因為它們是按照索引順序儲存資料的,如果有兩條資料具有相同的索引值,則它們將無法區分;而非聚簇索引可以是唯一的,也可以不是唯一的。

查詢效率不同:#

對於聚簇索引來說,查詢效率往往比非聚簇索引更高,因為聚簇索引將資料儲存在一起,查詢時可以更快地定位到所需的資料行;而對於非聚簇索引來說,查詢時需要先查詢索引,再根據索引找到對應的資料行,因此查詢效率相對較低。

插入資料效率不同:#

對於聚簇索引來說,由於資料按照索引順序儲存,因此在插入新資料時,可能需要移動已有的資料,因此插入資料的效率較低;而對於非聚簇索引來說,插入資料時只需要更新索引,因此效率相對較高。
需要注意的是,一個表只能有一個聚簇索引,因為資料只能按照一種順序儲存;而可以有多個非聚簇索引,以滿足不同的查詢需求。在設計資料庫時,需要根據具體的應用場景和查詢需求選擇不同的索引型別。

2.94 什麼是 MVCC?

MVCC,即Multi-Version Concurrency Control (多版本併發控制)。它是一種併發控制的方法,一般在資料庫管理系統中,實現對資料庫的併發訪問,在程式語言中實現事務記憶體。
通俗的講,資料庫中同時存在多個版本的資料,並不是整個資料庫的多個版本,而是某一條記錄的多個版本同時存在,在某個事務對其進行操作的時候,需要檢視這一條記錄的隱藏列事務版本id,比對事務id並根據事物隔離級別去判斷讀取哪個版本的資料

資料庫隔離級別讀已提交、可重複讀 都是基於MVCC實現的,相對於加鎖簡單粗暴的方式,它用更好的方式去處理讀寫衝突,能有效提高資料庫併發效能。

MVCC實現的關鍵知識點

事務版本號: 事務每次開啟前,都會從資料庫獲得一個自增長的事務ID,可以從事務ID判斷事務的執行先後順序。這就是事務版本號。

隱式欄位: 對於InnoDB儲存引擎,每一行記錄都有兩個隱藏列trx_id、roll_pointer,如果表中沒有主鍵和非NULL唯一鍵時,則還會有第三個隱藏的主鍵列row_id。

undo log : undo log,回滾日誌,用於記錄資料被修改前的資訊。在表記錄修改之前,會先把資料複製到undo log裡,如果事務回滾,即可以透過undo log來還原資料。

可以這樣認為,當delete一條記錄時,undo log 中會記錄一條對應的insert記錄,當update一條記錄時,它記錄一條對應相反的update記錄。

undo log有什麼用途呢?

  1. 事務回滾時,保證原子性和一致性。
  2. 用於MVCC快照讀。

版本鏈: 多個事務並行操作某一行資料時,不同事務對該行資料的修改會產生多個版本,然後透過回滾指標(roll_pointer),連成一個連結串列,這個連結串列就稱為版本鏈。如下:

其實,透過版本鏈,我們就可以看出事務版本號、表格隱藏的列和undo log它們之間的關係。我們再來小分析一下。

  1. 假設現在有一張core_user表,表裡面有一條資料,id為1,名字為孫權:

現在開啟一個事務A: 對core_user表執行update core_user set name ="曹操" where id=1,會進行如下流程操作
首先獲得一個事務ID=100
把core_user表修改前的資料,複製到undo log
修改core_user表中,id=1的資料,名字改為曹操
把修改後的資料事務Id=101改成當前事務版本號,並把roll_pointer指向undo log資料地址。

快照讀和當前讀

快照讀: 讀取的是記錄資料的可見版本(有舊的版本)。不加鎖,普通的select語句都是快照讀,如:

select * from core_user where id > 2;

當前讀:讀取的是記錄資料的最新版本,顯式加鎖的都是當前讀

select * from core_user where id > 2 for update;
select * from account where id>2 lock in share mode;

Read View

Read View是什麼呢? 它就是事務執行SQL語句時,產生的讀檢視。實際上在innodb中,每個SQL語句執行前都會得到一個Read View。
Read View有什麼用呢? 它主要是用來做可見性判斷的,即判斷當前事務可見哪個版本的資料~
Read View是如何保證可見性判斷的呢?我們先看看Read view 的幾個重要屬性

m_ids:當前系統中那些活躍(未提交)的讀寫事務ID, 它資料結構為一個List。
min_limit_id:表示在生成ReadView時,當前系統中活躍的讀寫事務中最小的事務id,即m_ids中的最小值。
max_limit_id:表示生成ReadView時,系統中應該分配給下一個事務的id值。
creator_trx_id: 建立當前read view的事務ID
Read view 匹配條件規則如下:

如果資料事務ID trx_id < min_limit_id,表明生成該版本的事務在生成Read View前,已經提交(因為事務ID是遞增的),所以該版本可以被當前事務訪問。
如果trx_id>= max_limit_id,表明生成該版本的事務在生成ReadView後才生成,所以該版本不可以被當前事務訪問。
如果 min_limit_id =<trx_id< max_limit_id,需腰分3種情況討論
(1).如果m_ids包含trx_id,則代表Read View生成時刻,這個事務還未提交,但是如果資料的trx_id等於creator_trx_id的話,表明資料是自己生成的,因此是可見的。
(2)如果m_ids包含trx_id,並且trx_id不等於creator_trx_id,則Read View生成時,事務未提交,並且不是自己生產的,所以當前事務也是看不見的;
(3).如果m_ids不包含trx_id,則說明你這個事務在Read View生成之前就已經提交了,修改的結果,當前事務是能看見的。

MVCC實現原理分析

查詢一條記錄,基於MVCC,是怎樣的流程

  1. 獲取事務自己的版本號,即事務ID
  2. 獲取Read View
  3. 查詢得到的資料,然後Read View中的事務版本號進行比較。
  4. 如果不符合Read View的可見性規則, 即就需要Undo log中歷史快照;
  5. 最後返回符合規則的資料

InnoDB 實現MVCC,是透過 Read View+ Undo Log 實現的,Undo Log 儲存了歷史快照,Read View可見性規則幫助判斷當前版本的資料是否可見。

2.95 mysql8.0版本後增加了什麼功能?

1.MySQL 8.0對redo log進行了重構,去掉了之前的鎖機制,採用了區間的方式來保證資料的一致性。這種改進使得redo log的寫入更加高效,提高了整體的執行效率。同時,MySQL 8.0還引入了Link_buf資料結構,使得整個模組變成了Lock_free的模式,進一步提升了效能。這種無鎖化的重構使得不同的執行緒在寫入redo_log_buffer時得以並行寫入,從而提高了資料庫的併發效能。

2.MySQL 8.0新增了隱藏索引和降序索引等特性。隱藏索引可以用來測試去掉索引對查詢效能的影響,幫助管理員找到最佳的索引策略。而降序索引則可以提高查詢的效率,特別是對於需要按照降序排列的查詢場景。這些索引最佳化使得MySQL在查詢效能方面有了顯著提升。

3.隨著非關係型資料庫和資料儲存的興起,MySQL 8.0也對NoSQL支援進行了最佳化。它不再依賴模式(schema),以更靈活的方式實現NoSQL功能,從而滿足使用者在資料處理方面的多樣化需求。這使得MySQL能夠更好地適應不同的應用場景,提供了更廣泛的資料儲存和查詢選項。

4.MySQL 8.0新增了SET PERSIST命令,允許使用者將配置持久化到資料目錄下的mysqld-auto.cnf檔案中。這樣,即使資料庫重啟,之前的配置也會得到保留,從而簡化了配置管理的工作。這使得管理員可以更加方便地管理和調整資料庫的配置,提高了資料庫的可維護性。

操作 SET PERSIST 命令,例如:

SET PERSIST max_connections = 500;
MySQL 會將該命令的配置儲存到資料目錄下的 mysqld-auto.cnf 檔案中,下次啟動時會讀取該檔案,用其中的配置來覆蓋預設的配置檔案。

5. MySQL 8.0 加入了視窗函式支援,如ROW_NUMBER()、RANK()、DENSE_RANK()等。視窗函式允許使用者在查詢中對資料集進行視窗分析,執行更復雜的計算任務。這使得MySQL在資料處理和分析方面的能力得到了顯著提升。透過視窗函式,使用者可以輕鬆地計算移動平均值、累計總和等,實現更高階的資料分析需求。

視窗函式有點像是 SUM()、COUNT() 那樣的集合函式,但它並不會將多行查詢結果合併為一行,而是將結果放回多行當中。也就是說,視窗函式是不需要 GROUP BY 的。

3. mongoDB相關面試題

3.1.簡述什麼是MongoDB?

MongoDB是一個基於分散式檔案儲存的資料庫,由C++語言編寫,旨在為Web應用提供可擴充套件的高效能資料儲存解決方案。它是一個介於關聯式資料庫和非關聯式資料庫之間的產品,是非關聯式資料庫當中功能最豐富,最像關聯式資料庫的。MongoDB支援的資料結構非常鬆散,是類似json的bson格式,因此可以儲存比較複雜的資料型別。MongoDB最大的特點是它支援的查詢語言非常強大,其語法有點類似於物件導向的查詢語言,幾乎可以實現類似關聯式資料庫單表查詢的絕大部分功能,而且還支援對資料建立索引。


3.2. MySQL與MongoDB之間最基本的差別是什麼?

ySQL和MongoDB之間有很多區別,以下是一些最基本的區別:

資料庫型別:MySQL是關係型資料庫,而MongoDB是非關係型資料庫。
資料儲存方式:MySQL支援多種引擎,不同引擎有不同的儲存方式,而MongoDB以類JSON的文件的格式儲存。
查詢語言:MySQL使用傳統SQL語句進行查詢,而MongoDB有自己的查詢方式(類似JavaScript的函式)。
索引:MySQL可以對錶中的列建立索引,而MongoDB可以對任何屬性建立索引。
擴充套件性:MySQL雖然也可以擴充套件,但需要更多的工作,而MongoDB是一個基於分散式檔案儲存的資料庫,可以方便地擴充套件到大量的資料和高併發。
延遲:由於MongoDB對寫入操作有較低的延遲,因此非常適合實時應用,而MySQL延遲相對較高。
事務:MySQL有完整的事務支援,而MongoDB不支援事務操作。
資料模式:MySQL需要預先定義欄位,而MongoDB是動態模式,同一個集合裡的文件不需要有相同的欄位和結構。

3.3 MongoDB成為最好NoSQL資料庫的原因是什麼?

MongoDB成為最好NoSQL資料庫的原因主要有以下幾點:

面向文件的儲存方式:MongoDB採用面向文件的儲存方式,這意味著它可以直接儲存資料物件,而不需要像關係型資料庫那樣將資料拆分成多個欄位。這種儲存方式使得MongoDB在處理複雜資料結構時更加靈活和高效。
高效能:MongoDB具有出色的效能,尤其是在處理大量資料和高併發訪問時。它採用二進位制協議,可以快速地讀寫資料,並且支援索引和查詢最佳化,進一步提高查詢效率。
高可用性:MongoDB具有高可用性,可以在多個節點之間進行資料複製和備份,確保資料的可靠性和容錯性。此外,MongoDB還支援自動分片和水平擴充套件,可以輕鬆地擴充套件資料庫的容量和效能。
易擴充套件性:MongoDB具有易於擴充套件的特性,可以方便地增加節點來處理更多的資料和請求。這對於需要處理大規模資料和高併發訪問的應用程式來說非常有用。
豐富的查詢語言:MongoDB採用類似JavaScript的查詢語言,可以輕鬆地執行復雜的查詢操作。這種查詢語言功能強大且易於使用,可以滿足各種資料檢索需求。
綜上所述,MongoDB的高效能、高可用性、易擴充套件性和豐富的查詢語言等特點使得它成為最好的NoSQL資料庫之一。

3.4 簡述MongoDB內部構造?

MongoDB的內部構造主要由以下幾個部分組成:

資料庫:MongoDB是一個基於文件的資料庫,可以建立多個資料庫。每個資料庫都有自己的檔案和索引,用於儲存和檢索資料。
集合:集合是MongoDB中儲存文件的容器。一個集合可以包含多個文件,每個文件都是一個鍵值對的形式,鍵是字串,值可以是各種資料型別。
文件:文件是MongoDB中的基本資料單位,它是一個鍵值對的集合。鍵是字串,值可以是各種資料型別,包括其他文件、陣列、日期、布林值等。
索引:索引是MongoDB中用於加速查詢的資料結構。它可以根據一個或多個欄位的值建立,使得查詢操作能夠快速找到滿足條件的文件。
複製:MongoDB支援資料複製,可以將資料從一個節點複製到另一個節點。這有助於提高資料的可用性和可靠性。
分片:MongoDB支援資料分片,可以將一個集合中的資料分散到多個節點上,以便提高資料的處理能力和儲存容量。
查詢語言:MongoDB使用一種類似JavaScript的查詢語言,用於檢索和運算元據。這種語言非常靈活,可以用於執行各種複雜的查詢操作。
總的來說,MongoDB的內部構造是基於文件的儲存模型,透過索引、複製和分片等技術來提高資料的處理能力和儲存容量。同時,MongoDB還提供了豐富的查詢語言和API介面,方便開發者進行應用程式的開發和整合。

相關文章