面試之關係型數據庫

零、關係型數據庫考點

  • 架構
  • 索引
  • 語法
  • 理論範式

1、架構

面:如何設計一個關係型數據庫?html

這主要考察咱們對關係型數據庫總體架構的把握,至關於讓咱們本身編寫一個RDBMS(關係型數據庫管理系統)。設計架構圖以下,能夠從下圖中的各個模塊進行回答。mysql

2、索引

面:爲何要使用索引?面試

答:爲了在數據庫中記錄較多的時候避免每次查詢都用全表掃描的方式,咱們須要一種更高效的機制,那就是索引相似與字典中的目錄,用來快速查詢數據。sql

面:什麼樣的信息能成爲索引?數據庫

答:能將某個記錄限定在必定查找範圍內的字段,就是一些關鍵信息,如主鍵、惟一鍵以及普通鍵等。segmentfault

索引的數據結構

爲了提升索引的性能,就要採起一些數據結構來加快索引的查詢。索引能夠採用的數據結構主要有如下幾種:數據結構

  • 創建二叉查找樹進行二分查找
  • 創建B-Tree結構進行查找
  • 創建B+-Tree結構進行查找
  • 創建Hash結構進行查找

二叉查找樹的弊端:當對索引的數據結構進行修改後,可能會退化成鏈表,即時間複雜度從O(logn)下降到O(n)。即便經過旋轉等方式使此樹可以保證二叉查找樹的結構,那麼還有一個影響性能的關鍵因素:I/O讀寫。深度過深的話,I/O讀寫次數也會變多,效率仍是很低。因此二叉查找樹不適用於創建索引。架構

B-Tree:經過分析二叉查找樹的弊端,咱們能夠下降樹的高度來減小I/O的次數。那麼B-Tree就能夠派上用場了。先看下什麼是B-Tree,這裏的B表示balance(平衡),B-Tree是一種多路自平衡的搜索樹。它相似於普通的平衡二叉樹,不一樣的一點是B-Tree容許每一個節點有更多的子節點。下圖是B-Tree的簡化圖:併發

B-Tree有如下特色:工具

  • 全部鍵值分佈在整棵樹中
  • 任何一個關鍵字出現且只出如今一個節點中
  • 搜索有可能在非葉子節點結束
  • 在關鍵字全集內作一次查找,性能逼近二分查找

B+-Tree:B+-Tree是B-Tree的變體,也是一種多路搜索樹,它與B-Tree的不一樣之處在於:

  1. 非葉子節點僅用來索引,數據都保存在葉子節點中
  2. 全部葉子節點均有一個鏈指針指向下一個葉子節點

簡化B+-Tree以下圖:

面:爲何B+-Tree相比B-Tree更適合用來作存儲索引?

  • B+樹的磁盤讀寫代價更低(內部節點不存儲真正數據信息)
  • B+樹的查詢效率更加穩定(全部關鍵字查詢都必須通過根節點到葉子節點,都是O(logn))
  • B+樹更有利於對數據庫的掃描(只需遍歷葉子節點,就能夠掃描到所有的關鍵字)

因爲B+-Tree的查詢必須進過根節點到葉子節點,通過屢次I/O,那麼是否可考慮Hash索引呢?

雖然Hash索引的查詢效率比B+-Tree索引的查詢效率要高,但同時它也有許多的弊端:

  • 僅僅能知足「=」,「IN」,不能使用範圍查詢
  • 沒法被用來避免數據的排序操做
  • 不能利用部分索引鍵查詢
  • 不能避免表掃描
  • 遇到大量Hash值相等後的狀況性能並不必定就會比B+-Tree索引高

因此綜上,MySQL採用B+樹來做爲索引的數據結構。

密集索引和稀疏索引

面:密集索引和稀疏索引的區別

答:

  • 密集索引文件中的每一個搜索碼都對應一個索引值
  • 稀疏索引文件只爲搜索碼的某些值創建索引項
  • 密集索引比稀疏索引更快地定位一條記錄
  • 稀疏索引所佔空間小,而且插入和刪除時所需維護的開銷也小

在MySQL中的InnoDB中,關於密集索引的知識點以下:

  • 若一個主鍵被定義,則該主鍵做爲密集索引
  • 若沒有主鍵被定義,該表的第一個惟一非空索引則做爲密集索引
  • 若不知足以上條件,InnoDB內部會生成一個隱藏主鍵(密集索引)

面:如何定位並優化慢查詢SQL?(開放性)

答:

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

實例:首先查看慢日誌(DML SQL執行時間大於必定長度)的相關配置。

show VARIABLES like '%query%'

在返回的結果中,關注三個變量:

Variable_name value
long_query_time 1.000000 #慢查詢時間的閾值
slow_query_log ON #是否開啓記錄慢查詢日誌
slow_query_log_file /home/mysql/data3001/mysql/slow_query.log #慢日誌路徑
show status like '%slow_queries%' #查看當前慢查詢的條數

運行語句SELECT name FROM chapter,chpater表中有50多萬條記錄,耗時23s。運行上面的查詢慢查詢條數的SQL語句,會發現增長了1,接下來經過explain工具分析。運行語句explain SELECT name FROM chapter,關注返回結果的type列發現結果是ALL,意味着是走的全表掃描,那麼確實是不快的。咱們來看下查詢走索引的,explain SELECT id FROM chapter,type列的結果是index,走的是索引(但不是主鍵索引,看key列結果是fk_chapter_novel,走的是外鍵索引,說明主鍵索引不必定比其餘索引快)。此時運行SELECT id FROM chapte只耗時2.9秒。來強制走下主鍵索引,運行語句SELECT id FROM chapter FORCE INDEX(PRIMARY),耗時23s,運行EXPLAIN SELECT id FROM chapter FORCE INDEX(PRIMARY)發現是走了主鍵索引的,可是耗時卻和全表掃描差很少了。

面:索引是創建的越多越好嗎?

答:答案固然是否認的。

  • 數據量小的表不須要創建索引,創建會增長額外的索引開銷
  • 數據變動須要維護索引,所以更多的索引意味着更多的維護成本

3、鎖

關於數據庫鎖部分主要回答以下問題:

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

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

答:

  • MyISAM默認使用的是表級鎖,不支持行級鎖
  • InnoDB默認使用的是行級鎖,也支持表級鎖

共享鎖和排它鎖的兼容性

- X S
X 衝突 衝突
S 衝突 兼容

MyISAM適合的場景

  • 頻繁執行全表count語句
  • 對數據進行增刪改的頻率不高(表級鎖,每次都會鎖住整張表),查詢很是頻繁
  • 沒有事務

InnoDB適合的場景

  • 數據增刪改查都至關頻繁(行級鎖)
  • 可靠性要求比較高,要求支持事務

數據庫鎖的分類

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

面:數據庫事務的四大特性

答:ACID

  1. 原子性(Atomic):事務中的全部操做要麼所有執行,要麼所有失敗回滾
  2. 一致性(Consistency):確保數據庫的狀態從一個一致性狀態轉變爲另外一個一致性狀態,一致性狀態是指數據庫中的數據應知足完整性約束
  3. 隔離性(Isolation):多個事務併發執行時,一個事務的執行不該該影響其餘事務的執行
  4. 持久性(Durability):一個事務提交後,它對數據庫的修改應該永久保存在數據庫中

面:能說說事務隔離級別以及各級別下的併發訪問問題嗎?

答:MySQL事務的隔離級別由低到高分別是read uncommitted(未提交讀)、read committed(提交讀)、repeatable read(可重複讀)、serializable(串行化)。併發訪問問題及對應解決的事務隔離級別以下:

  • 更新丟失(一個事務的更新覆蓋掉了另外一個事務的更新):MySQL中全部事務隔離級別在數據庫層面上都可避免

    實例以下圖:

  • 髒讀(一個事務讀到另一個未提交事務的數據):READ-COMMITTED事務隔離級別及以上可避免

  • 不可重複讀(事務A屢次讀取同一數據,事務B在事務A讀取的同時對該數據作了更新並提交,致使事務A屢次讀取到的結果不一致):REPEATABLE-READ事務隔離級別及以上可避免

  • 幻讀(事務A屢次讀取與搜索條件相匹配的若干行,事務B用插入或刪除行的方式來修改事務A的結果集,致使事務A出現了「幻覺」):SERIALIZABLE事務隔離級別可避免

當前讀與快照讀

當前讀的數據是最新的,而快照讀讀取的是快照。當前讀主要是如下SQL:

select...lock in share mode
select...for update
update,delete,insert

面:能說說InnoDB可重複讀隔離級別下如何避免幻讀嗎?

答:表面上來看是經過僞MVCC的快照讀(非阻塞讀)實現的,但本質確實經過next-key鎖即行鎖+gap鎖實現的。

4、語法

SELECT 
    column_1, column_2, ...
FROM
    table_1
[INNER | LEFT |RIGHT] JOIN table_2 ON conditions
WHERE
    conditions
GROUP BY column_1
HAVING group_conditions
ORDER BY column_1
LIMIT offset, length;

參考資料

慕課網 劍指Java面試-Offer直通車

由 B-/B+樹看 MySQL索引結構

稠密索引與稀疏索引

相關文章
相關標籤/搜索