博客 / 詳情

返回

騰訊一面:那些數據庫的高頻問題

幾個月前,有位朋友去騰訊面試,他説被問到了一系列關於數據庫的問題,比如三大範式是什麼,它們在數據庫設計中的作用是什麼?在數據庫中,常見的併發問題有哪些?如何通過事務管理避免這些問題?什麼是 MVCC(多版本併發控制)?本文將跟大家一起來探討如何回答這些問題。

這些數據庫相關的問題之所以在面試中頻繁出現,是因為在實際的開發工作中,數據庫的設計與優化、事務管理等方面至關重要。如果對這些知識掌握不紮實,可能會導致數據存儲不合理、查詢效率低下,甚至在高併發場景下出現數據不一致等嚴重問題。然而,許多新手在剛開始接觸數據庫開發時,往往對這些基礎知識不夠重視,直到在實際項目中遇到性能瓶頸或者數據異常時,才意識到這些知識的重要性。因此,面試官通常會在面試中重點考察你對這些數據庫核心知識的理解和掌握程度,以判斷你是否具備解決實際問題的能力。

1.三大範式是什麼,它們在數據庫設計中的作用是什麼?
2. 為什麼在優化 SQL 查詢時需要使用 EXPLAIN 命令?它能提供哪些關鍵信息?
3. 列舉並簡要説明常見的索引類型
4. 請列舉索引失效的幾種常見場景
5. 在什麼情況下應該使用索引來優化查詢?
6. 什麼是數據庫事務?它的基本特性是什麼?
7. 事務的隔離級別是什麼?它如何影響併發事務的執行?
8. 在數據庫中,常見的併發問題有哪些?如何通過事務管理避免這些問題?
9. 什麼是 MVCC(多版本併發控制)?
10. 為什麼 MySQL 默認的可重複讀隔離級別能夠在很大程度上避免幻讀?在高併發環境下,這兩種解決方案的效果如何?
11. 數據庫中的三種日誌類型分別是什麼?它們各自的作用是什麼?

1. 三大範式是什麼,它們在數據庫設計中的作用是什麼?

  • 1NF(第一範式) :第一範式要求一行中的每個單元格都應該有單一值,且不能出現重複列。也就是説表中一行中的列值是一個而不能是多個,也不能出現重複的列。
  • 2NF(第二範式) :在第一範式的基礎上,第二範式要求每張表都應該有一個單一目的。也就是説這張表只能代表一種實體,而表中的每一列都應該用來描述那個實體。
  • 3NF(第三範式) :在第二範式的基礎上,第三範式表示,表中的列不能派生自其他列。也就是説表中的列不能通過其他列得到。

2. 為什麼在優化 SQL 查詢時需要使用 EXPLAIN 命令?它能提供哪些關鍵信息?

explain 命令

  • 作用:作用於你寫的 sql 語句,數據庫會返回一個執行計劃
  • 執行計劃會有很多字段

    • type:指查詢到所需行的方式,從好到壞的順序:system>const>eq_ref>ref>range>index>ALL
    • possible_keys:候選的索引
    • key:實際使用的索引
    • rows:掃描行數
    • filtered:所需數據行佔 rows 的比例

3. 列舉並簡要説明常見的索引類型

  • 按 數據結構 分類:B+樹索引,Hash 索引,Full-text 索引
  • 按 物理存儲 分類:聚簇索引(主鍵索引),二級索引(輔助索引)
  • 按 字段特性 分類:主鍵索引,唯一索引,普通索引,前綴索引
  • 按 字段個數 分類:單列索引,聯合索引

4. 請列舉索引失效的幾種常見場景

  • 對索引使用左或者右模糊匹配,如 like '%xx',like '%xx%'
  • 對索引使用函數
  • 對索引進行表達式計算
  • 對索引隱式類型轉換
  • 聯合索引非最左匹配
  • where 子句中的 or
  • 數據量太小,MySQL 覺得全表掃描更快

5. 在什麼情況下應該使用索引來優化查詢?

  • 字段具有唯一性限制
  • 經常用於 where 查詢條件的字段,如果不是一個字段,可以建立聯合索引
  • 經常用於 group by 和 order by 的字段,這樣查詢的時候就不需要再次排序了,建立索引後,在 B+Tree 中的記錄都是排序好的。

6. 什麼是數據庫事務?它的基本特性是什麼?

  • 事務是代表單個工作單元的一組 SQL 語句,當我們需要對數據庫進行多次更改的情況下,要使用事務,我們希望所有這些更改作為一個單元一起成功或失敗
  • 事務的四大特性 (ACID)

    • 原子性(Atomicity) :事務中的所有操作要麼全部完成,要麼全部不完成;
    • 一致性(Consistency) :事務完成後,數據庫必須從一個一致狀態轉化到另一個一致狀態,數據庫始保持一致的狀態;
    • 隔離性(Islation) :一個事務的執行不應影響其他事務的執行;
    • 持久性(Durability) :一旦事務提交,其結果應該永久保存在數據庫中,即使系統發生故障;

7. 事務的隔離級別是什麼?它如何影響併發事務的執行?

標準的 SQL 定義了 4 個事務隔離級別,隔離級別逐漸增高,性能和可擴展性逐漸降低,因為限制了併發。在 MySQL 中,默認的事務隔離級別是‘可重複讀’。

  • 讀未提交 :允許讀取未提交的數據,最低的隔離級別
  • 讀已提交 :給予了我們的事務一定的隔離,使得該事務只能讀取已提交的數據,避免了髒讀。
  • 可重複讀 :我們讀取的數據是可重複和一致的,就算有其他事務更改了數據,我們會看到首次讀取就創建的快照。
  • 序列化 :它能保證當有別的事務在更新數據時,我們的事務能夠知曉變動,如果有其他事務修改了可能影響查詢結果的數據,我們的事務必須等它們完成,這樣事務就會按序列化執行。

8. 在數據庫中,常見的併發問題有哪些?如何通過事務管理避免這些問題?

  1. 丟失更新
  • 當兩個事務嘗試更新相同的數據並且沒有上鎖時,就會發生這種情況,比如兩個事務更新同一條記錄的不同列的信息,較晚提交的事務會覆蓋較早事務做的更改,使得較早事務做的更改缺失。
  • 使用鎖,防止兩個事務同時更新同樣的數據,MySQL 提供的默認鎖的鎖粒度是行級鎖。
  1. 髒讀
  • 一個事務讀取了尚未被提交的數據,如果該數據被退回的話,該事務就是讀取了一個不存在的數據,就是髒讀。
  • 為了解決這個問題,我們需要為事務建立隔離級別,“讀已提交”,這樣事務修改的數據不會立馬被其他事務讀取,除非它提交了。
  1. 不可重複讀(不一致讀)
  • 當我們在事務中添加更多隔離時,我們可以保證事務只能讀取已提交的數據,但如果在事務過程中,讀取了某個數據兩次,並得到了不同的結果就是不可重複讀問題。
  • 我們就需要增加事務隔離級別,我們要將它與其他事務隔離,“可重複讀”,確保數據更改對該事務不可見,只看事務開始前那一刻的數據信息。
  1. 幻讀
  • 對於突然出現或者缺失的數據,我們無法在查詢中看到它們,因為它們是在執行查詢後才添加、更新、刪除的。
  • 為此,我們有另一個隔離級別為”序列化“,它能保證當有別的事務在更新數據時,我們的事務能夠知曉變動,如果有其他事務修改了可能影響查詢結果的數據,我們的事務必須等它們完成,這樣事務就會按序列化執行。

9. 什麼是 MVCC(多版本併發控制)?

MVCC(多版本併發控制) 是一種用於數據庫管理系統的併發控制機制,它的目的是提高數據併發訪問的效率,減少鎖競爭,降低對鎖的依賴。MVCC 具體實現是通過 Read View版本鏈機制

  • Read View 是實現 MVCC 機制的一個關鍵概念,包含四個重要字段:

    • m_ids:當前數據庫中活躍事務的事務 ID 列表,活躍事務是指已啓動但尚未提交的事務。
    • min_trx_id:指的是 m_ids 中的最小事務 ID。
    • max_trx_id:數據庫中最大的事務 ID 加 1。也就是説,它表示當前數據庫中還未提交的最大事務 ID。
    • creator_trx_id:創建該 Read View 的事務 ID。
  • 在 InnoDB 存儲引擎中,每條記錄的行格式包含兩個隱藏字段:

    • trx_id:每當一個事務對某條記錄進行更改時,系統會將該事務的事務 ID 記錄在 trx_id 中。
    • roll_pointer:每次修改記錄時,舊版本的記錄會被寫入 undo 日誌,這個字段指向舊版本記錄的地址,通過這個指針可以追溯到修改前的記錄,這就是所謂的版本鏈。
具體實現過程:
  • 通過 Read View 和版本鏈機制,InnoDB 實現了事務的併發控制。在事務開始時,系統會創建一個 Read View,並根據該事務的可見性來讀取數據:

    • 可見的事務 ID 是小於 min_trx_id 的事務 ID,這些事務的數據對當前事務是可見的。
    • 不可見的事務 ID 是大於等於 max_trx_id 的事務 ID,當前事務無法讀取這些事務的數據。
  • 當查詢數據時,系統會檢查每條記錄的 trx_id 來判斷其是否符合事務的可見性要求。如果該記錄的 trx_id 不符合,則系統會通過 roll_pointer 找到該記錄的舊版本,從而實現數據的讀取。
  • 通過這種機制,InnoDB 能夠在高併發環境下保持事務的隔離性,同時確保每個事務能讀取到基於其創建時的 Read View 可見的數據。這種多版本併發控制(MVCC)技術有效地解決了讀寫衝突的問題,並允許事務以一致的方式讀取數據。

10. 為什麼 MySQL 默認的可重複讀隔離級別能夠在很大程度上避免幻讀?在高併發環境下,這兩種解決方案的效果如何?

  • MySQL 雖然支持 4 種隔離級別,但是與 SQL 標準種規定的各級隔離級別允許發生的現象卻有些出入。MySQL InnoDB 引擎的默認隔離級別雖然是可重複讀,但是它很大程度上避免了幻讀現象,解決的方案有兩種:

    • 針對快照讀,普通的 select 語句,是通過 MVCC 的方式解決了幻讀。
    • 針對當前讀,select…for update 等,是通過加臨界鎖(記錄鎖+間隙鎖)。當執行當前讀時,會在範圍加上臨界鎖,其他事務如果在鎖的範圍內插入或刪除一條記錄,就會被阻塞,很好地避免了幻讀問題。

11. 數據庫中的三種日誌類型分別是什麼?它們各自的作用是什麼?

  1. undo log(回滾日誌) :是 InnoDB 存儲引擎層生成的日誌,實現了事務中的原子性,主要用於事務回滾和 MVCC
  2. redo log(重做日誌) :是 InnoDB 存儲引擎層生成的日誌,實現了事務中的持久性,主要用於掉電等故障恢復。
  3. binlog(歸檔日誌) :是 Server 層生成的日誌,主要用於數據備份和主從複製。

就業陪跑訓練營學員投稿

歡迎關注 ❤

我們搞了一個免費的面試真題共享羣,互通有無,一起刷題進步。

沒準能讓你能刷到自己意向公司的最新面試題呢。

感興趣的朋友們可以加我微信:wangzhongyang1993,備註:面試羣。

user avatar aipaobudehoutao 頭像 wolun 頭像 shenge 頭像
3 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.