Java後端面試系列-數據庫篇

1 概述

1.1 關係型數據庫主要考點

在這裏插入圖片描述

1.2 一個面試題引發的"血案"

  • 問:如何設計一個關係型數據庫?
  • 答:
    在這裏插入圖片描述
  1. 存儲(文件系統):持久化
  2. 程序實例:包含以下8個模塊。
    存儲模塊:磁盤IO速率是瓶頸,得設計優化方法,比如:一次讀取多條數據進入內存。
    緩存機制:不宜過大,且有淘汰機制比如:LRU
    SQL解析:將SQL語句進行解析
    日誌管理:記錄操作記錄,比如binlog
    權限劃分:記錄多用戶管理的權限劃分模塊,一般DBA關心
    容災機制:
    索引管理:優化數據查詢速率
    鎖管理:使之支持併發操作

2 索引模塊

常見問題

  • 爲什要使用索引?
  • 什麼樣的信息能夠成爲索引?
  • 索引的數據結構?
  • 密集索引和稀疏索引的區別?

2.1 爲什要使用索引

答:快速查詢數據。

若使用全表掃描,在數據量小的時候沒有問題,一旦數據量大了,查詢效率會降低;而索引類似於字典的偏旁部首,先找偏旁部首,可以更快速找到想要的數據。

2.2 什麼樣的信息能夠成爲索引

答:主鍵、唯一鍵以及普通鍵等

2.3 索引的數據結構

  • 生成索引,建立二叉查找樹進行二分查找
  • 生成索引,建立B-Tree結構進行查找
  • 生成索引,建立B±Tree結構進行查找
  • 生成索引,建立Hash結構進行查找

2.3.1 二叉查找樹上陣

在這裏插入圖片描述
首先先說二叉查找樹,這是會出現一個問題:當往一邊增加會出現下面的情況:

在這裏插入圖片描述
結果是:二叉查找樹退化成一個鏈表,時間複雜度爲O(N)。

此時一個解決辦法是通過旋轉,維持樹的平衡,比如:平衡二叉樹、紅黑樹。但是又有一個問題:磁盤IO是關鍵,而磁盤IO訪問次數與樹的深度直接相關,比如訪問數字“6”,就需要三次,還可以優化嗎?

很明顯,問題出在這些平衡樹的子樹最多兩個,能不能多個呢,此時B-Tree站出來了。

2.3.2 B-Tree

在這裏插入圖片描述
定義:

  • 根節點至少包括兩個孩子
  • 樹中每個節點最多包含有m個孩子(m>=2)
  • 除根節點和葉節點外,其他每個節點至少有ceil(m/2)個孩子
  • 所有葉子節點都位於同一層
  • 假設每個非終端節點中包含有nn個關鍵字信息,其中:
    • Ki(i=1...n)K_i(i=1...n)爲關鍵字,且關鍵字按順序升序排序k(i1)<Kik(i-1)<K_i
    • 關鍵字的個數nn必須滿足:[ceil(m/2)1]<=n<=m1[ceil(m/2)-1] <= n <= m-1
    • 非葉子結點的指針:P[1],P[2],…,P[M];其中P[1]指向關鍵字小於K[1]的子樹,P[M]指向關鍵字大於K[M-1]的子樹,其他P[i]指向關鍵字屬於(K[i-1],K[i])的子樹

看起來,B-Tree已經不錯了,但還有更好地選擇。

2.3.3 B+ -Tree

在這裏插入圖片描述
B+樹是B樹的變體,其定義基本與B樹相同,除了

  • 非葉子結點的子樹指針與關鍵字個數相同
  • 非葉子結點的子樹指針P[i],指向關鍵字值[K[i],K[i+1])的子樹
  • 非葉子結點僅用來索引,數據都保存的葉子節點中
  • 所有葉子節點均有一個鏈指針指向下一個葉子節點

2.3.4 結論

B+Tree更適合用來做存儲索引

  • B+樹的磁盤讀寫代價更低
  • B+樹的查詢效率更加穩定
  • B+樹更有利於對數據庫的掃描

2.3.5 Hash索引

在這裏插入圖片描述
優點:查詢效率高
缺點:

  • 僅能滿足“=”,“IN”,不能使用範圍查詢
  • 無法用來避免數據的排序操作
  • 不能利用部分索引建查詢
  • 不能避免表掃描
  • 遇到大量Hash值相等的情況後性能並不一定比B-tree索引高

2.3.6 BitMap索引

在這裏插入圖片描述

  • 高效,適合統計
  • 只適用於某個字段只有有限個取值的情況下
  • 鎖的粒度大

2.4 密集索引和稀疏索引的區別

  • 密集索引文件中的每個搜索碼值都對應一個索引值
  • 稀疏索引文件置爲索引碼的某些值建立索引項
    在這裏插入圖片描述
    在這裏插入圖片描述

2.4.1 額外知識

針對Mysql,MyISAM都是稀疏索引,而InnoDB有且僅有一個密集索引

InnoDB

  • 若一個主鍵被定義,該主鍵則作爲密集索引
  • 若沒有主鍵被定義,該表第一個唯一非空索引則作爲密集索引
  • 如不滿足上述條件,則InnoDB內部會生成一個隱藏主鍵(密集索引)
  • 非主鍵索引存儲相關鍵位和其對應的主鍵值,包含兩次查找

在這裏插入圖片描述
實際的樣子
在這裏插入圖片描述
上面兩個文件就是InnoDB的,下面三個是MyISAM

  • .frm:代表表的結構
  • .ibd:代表InnoDB表的數據和索引
  • .MYD:代表MyISAM的數據
  • .MYI:代表MyISAM的索引

2.5 衍生出來的問題,以mysql爲例

  • 如何定位並優化慢查詢Sql
  • 聯合索引的最左匹配原則的成因
  • 索引是建立得越多越好嗎

2.5.1 如何定位並優化慢查詢Sql

大致思路如下:

  1. 根據慢日誌定位慢查詢sql
  2. 使用 explain等工具分析sql
  3. 修改sql或者儘量讓sql走索引

(1)根據慢日誌定位慢查詢sql

SHOW VARIABLES LIKE '%quer%';

查詢一些系統變量:
在這裏插入圖片描述
主要由三個變量值得注意:
long_query_time :查過這個時間,就算是個慢查詢
slow_query_log :是否開啓慢差日誌
slow_query_log_file:慢差日誌保存位置

修改命令如下:

SET GLOBAL long_query_time = 1;

SET GLOBAL slow_query_log = ON;

SET GLOBAL slow_query_log_file = 'E:\\program-software\\mysql5.7.23\\slow.log';

開始查詢:

SELECT NAME FROM t_teacher ORDER BY NAME DESC;

可以打開slow.log
在這裏插入圖片描述
花了近10秒

也可用通過命令查詢本次連接慢差的次數:
SHOW STATUS LIKE '%slow_queries%';
在這裏插入圖片描述

(2)根據explain工具分析這條sql

EXPLAIN SELECT NAME FROM t_teacher ORDER BY NAME DESC;

重點是看typeExtra兩個字段

  • type
    在這裏插入圖片描述
  • extra
    在這裏插入圖片描述

(3)修改sql或者儘量讓sql走索引

EXPLAIN SELECT id FROM t_teacher ORDER BY id DESC;

加索引

ALTER TABLE t_teacher ADD INDEX idx_name(NAME);

2.5.2 聯合索引的最左匹配原則的成因

在這裏插入圖片描述

2.5.3 索引是建立得越多越好嗎

不是。

  1. 數據量小的表不需要建立索引,建立會增加額外的開銷。
  2. 數據變更需要維護索引,因此需要更多的維護成本
  3. 更多的索引意味着需要更多的空間開銷。

3 鎖模塊

常見問題

  • MyISAM與InnoDB關於鎖方面的區別是什麼
  • 數據庫事務的四大特性
  • 事務隔離級別以及各級別下的併發訪問問題
  • InnoDB可重複讀隔離級別下如何避免幻讀
  • RC、RR級別下的InnoDB的非阻塞讀如何實現

3.1 MyISAM與InnoDB關於鎖方面的區別是什麼

在這裏插入圖片描述
InnoDB中在SQL沒用到索引時,走的表級鎖;用到索引,走的行級索。
在這裏插入圖片描述

3.2 適用場景

3.2.1 MyISAM適合的場景

  • 頻繁使用全表count語句
  • 對數據庫進行增刪改的頻率不高,查詢非常頻繁
  • 沒有十五

3.2.2 InnoDB適合的場景

  • 數據庫的增刪改操作很多時
  • 對數據庫的可靠性要求高時,要求支持事務

3.3 鎖的分類

  • 按鎖的粒度劃分,可分爲表級鎖、行級鎖、頁級鎖
  • 按鎖級別劃分,可分爲共享鎖、排它鎖
  • 按加鎖方式劃分,可分爲自動鎖、顯式鎖
  • 按操作分,可分爲DML鎖,DDL鎖
  • 按使用方式劃分,可分爲樂觀鎖,悲觀鎖

3.4 數據庫事務的四大特性

ACID

  • 原子性
  • 一致性
  • 隔離性
  • 持久性

3.5 事務隔離級別以及各級別下的併發訪問問題

問題:

  1. 更新丟失——read uncommitted(讀未提交)解決
  2. 髒讀——read committed(讀已提交)解決
  3. 不可重複讀——repeatable read (可重複讀)解決
  4. 幻讀——serializable(序列化)解決

3.6 InnoDB可重複讀隔離級別下如何避免幻讀

  • 表象:快照讀(非阻塞讀)——僞MVCC
  • 內在:next-key鎖(行鎖+gap鎖

問:對主鍵索引或唯一索引會用Gap鎖嗎?

  • 如果where條件全部命中,則不會用Gap鎖,只會加記錄鎖。
    在這裏插入圖片描述
  • 如果where條件部分命令或全部不命中,則會用Gap鎖,記錄鎖。

Gap鎖會用在費唯一索引或者不走索引的當前讀中

  • 非唯一索引
  • 不走索引

3.7 RC、RR級別下的InnoDB的非阻塞讀如何實現

  • 數據行裏的DB_TRX_ID(最後一次修改的事務ID)、DB_ROLL_PTR(回滾指針,指向undo log中修改前的行)、DB_ROW_ID(插入數據時自增)字段
  • undo日誌(存儲的老版本數據,分別insert undo log和update undo log)
    insert undo log指定的insert操作的undo log,只在事務回滾時需要,並且在提交事務之後就會丟棄;
    update undo log:存儲update、detele操作,不僅在事務回滾時需要,快照讀時也需要,只有當快照中不涉及該日誌中的操作,纔會被刪除。
    在這裏插入圖片描述
  • read view(還會根據你的事務ID得出你可見的數據,因爲越新打開的事務,事務ID越大)

:只有非序列化隔離級別下的select語句爲快照讀;其他是當前讀,比如:select .. lock in share modeselect ... for updateupdate delete insert

4 語法部分

關鍵語法:

  • GROUP BY
  • HAVING
  • 統計相關:CUNT、SUM、MAX、MIN、AVG

4.1 GROUP

  • 滿足“select 子句中的列名必須爲分組列或列函數”
  • 列函數對於group by子句定義的每個組各返回一個結果
    在這裏插入圖片描述
# 查詢所有同學的學號、選課數、總成績
SELECT student_id,COUNT(course_id),SUM(score) 
FROM score 
GROUP BY student_id

# 查詢所有同學的學號、姓名、選課數、總成績
SELECT score.student_id,student.`name`,COUNT(course_id),SUM(score) 
FROM score, student 
WHERE score.`student_id` = student.`student_id` 
GROUP BY score.student_id

4.2 HAVING

  • 通常與GROUP BY子句一起使用
  • WHERE過濾行,HAVING過濾組
  • 出現在同意sql的順序:WHERE>GROUP BY>HAVING
# 查詢平均成績大於60分的同學的學號和平均成績
SELECT student_id, AVG(score) 
FROM score 
GROUP BY student_id 
HAVING AVG(score) > 60

# 查詢沒有學全所有課的同學的學號、姓名
SELECT s.student_id, s.name 
FROM student s, score sco 
WHERE s.student_id = sco.student_id 
GROUP BY sco.student_id 
HAVING COUNT(sco.course_id) != (SELECT COUNT(*) FROM course);

5 數據庫三範式

  • 1NF:字段不可分;

  • 2NF:有主鍵,非主鍵字段依賴主鍵;

  • 3NF:非主鍵字段不能相互依賴,不存在傳遞依賴

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章