天天看點

快問快答,MySQL面試奪命20問

資料庫架構

說說MySQL 的基礎架構圖

給面試官講一下 MySQL 的邏輯架構,有白闆可以把下面的圖畫一下。

快問快答,MySQL面試奪命20問

Mysql邏輯架構圖主要分三層:

(1)第一層負責連接配接處理,授權認證,安全等等 

(2)第二層負責編譯并優化SQL 

(3)第三層是存儲引擎。

一條SQL查詢語句在MySQL中如何執行的?
  • 先檢查該語句是否有權限

    ,如果沒有權限,直接傳回錯誤資訊,如果有權限會先查詢緩存(MySQL8.0 版本以前)。

  • 如果沒有緩存,分析器進行詞法分析

    ,提取 sql 語句中 select 等關鍵元素,然後判斷 sql 語句是否有文法錯誤,比如關鍵詞是否正确等等。

  • 最後優化器确定執行方案進行權限校驗,如果沒有權限就直接傳回錯誤資訊,如果有權限就會調用資料庫引擎接口

    ,傳回執行結果。

SQL 優化

日常工作中你是怎麼優化SQL的?

可以從這幾個次元回答這個問題:

1,優化表結構

(1)盡量使用數字型字段

若隻含數值資訊的字段盡量不要設計為字元型,這會降低查詢和連接配接的性能,并會增加存儲開銷。這是因為引擎在處理查詢和連接配接時會逐個比較字元串中每一個字元,而對于數字型而言隻需要比較一次就夠了。

(2)盡可能的使用 varchar 代替 char

變長字段存儲空間小,可以節省存儲空間。

(3)當索引列大量重複資料時,可以把索引删除掉

比如有一列是性别,幾乎隻有男、女、未知,這樣的索引是無效的。

2,優化查詢

  • 應盡量避免在 where 子句中使用!=或<>操作符
  • 應盡量避免在 where 子句中使用 or 來連接配接條件
  • 任何查詢也不要出現select *
  • 避免在 where 子句中對字段進行 null 值判斷

3,索引優化

  • 對作為查詢條件和 order by的字段建立索引
  • 避免建立過多的索引,多使用組合索引
怎麼看執行計劃(explain),如何了解其中各個字段的含義?

在 select 語句之前增加 explain 關鍵字,會傳回執行計劃的資訊。

快問快答,MySQL面試奪命20問

(1)id 列:是 select 語句的序号,MySQL将 select 查詢分為簡單查詢和複雜查詢。

(2)select_type列:表示對應行是是簡單還是複雜的查詢。

(3)table 列:表示 explain 的一行正在通路哪個表。

(4)type 列:最重要的列之一。表示關聯類型或通路類型,即 MySQL 決定如何查找表中的行。從最優到最差分别為:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

(5)possible_keys 列:顯示查詢可能使用哪些索引來查找。

(6)key 列:這一列顯示 mysql 實際采用哪個索引來優化對該表的通路。

(7)key_len 列:顯示了mysql在索引裡使用的位元組數,通過這個值可以算出具體使用了索引中的哪些列。

(8)ref 列:這一列顯示了在key列記錄的索引中,表查找值所用到的列或常量,常見的有:const(常量),func,NULL,字段名。

(9)rows 列:這一列是 mysql 估計要讀取并檢測的行數,注意這個不是結果集裡的行數。

(10)Extra 列:顯示額外資訊。比如有 Using index、Using where、Using temporary等。

關心過業務系統裡面的sql耗時嗎?統計過慢查詢嗎?對慢查詢都怎麼優化過?

我們平時寫Sql時,都要養成用explain分析的習慣。慢查詢的統計,運維會定期統計給我們

優化慢查詢思路:

  • 分析語句,是否加載了不必要的字段/資料
  • 分析 SQL 執行句話,是否命中索引等
  • 如果 SQL 很複雜,優化 SQL 結構
  • 如果表資料量太大,考慮分表

索引

聚集索引與非聚集索引的差別

可以按以下四個次元回答:

(1)一個表中隻能擁有一個聚集索引,而非聚集索引一個表可以存在多個。

(2)聚集索引,索引中鍵值的邏輯順序決定了表中相應行的實體順序;非聚集索引,索引中索引的邏輯順序與磁盤上行的實體存儲順序不同。

(3)索引是通過二叉樹的資料結構來描述的,我們可以這麼了解聚簇索引:索引的葉節點就是資料節點。而非聚簇索引的葉節點仍然是索引節點,隻不過有一個指針指向對應的資料塊。

(4)聚集索引:實體存儲按照索引排序;非聚集索引:實體存儲不按照索引排序;

為什麼要用 B+ 樹,為什麼不用普通二叉樹?

可以從幾個次元去看這個問題,查詢是否夠快,效率是否穩定,存儲資料多少,以及查找磁盤次數,為什麼不是普通二叉樹,為什麼不是平衡二叉樹,為什麼不是B樹,而偏偏是 B+ 樹呢?

(1)為什麼不是普通二叉樹?

如果二叉樹特殊化為一個連結清單,相當于全表掃描。平衡二叉樹相比于二叉查找樹來說,查找效率更穩定,總體的查找速度也更快。

(2)為什麼不是平衡二叉樹呢?

我們知道,在記憶體比在磁盤的資料,查詢效率快得多。如果樹這種資料結構作為索引,那我們每查找一次資料就需要從磁盤中讀取一個節點,也就是我們說的一個磁盤塊,但是平衡二叉樹可是每個節點隻存儲一個鍵值和資料的,如果是B樹,可以存儲更多的節點資料,樹的高度也會降低,是以讀取磁盤的次數就降下來啦,查詢效率就快啦。

(3)為什麼不是 B 樹而是 B+ 樹呢?

B+ 樹非葉子節點上是不存儲資料的,僅存儲鍵值,而B樹節點中不僅存儲鍵值,也會存儲資料。innodb中頁的預設大小是16KB,如果不存儲資料,那麼就會存儲更多的鍵值,相應的樹的階數(節點的子節點樹)就會更大,樹就會更矮更胖,如此一來我們查找資料進行磁盤的IO次數有會再次減少,資料查詢的效率也會更快。

B+ 樹索引的所有資料均存儲在葉子節點,而且資料是按照順序排列的,連結清單連着的。那麼 B+ 樹使得範圍查找,排序查找,分組查找以及去重查找變得異常簡單。

Hash 索引和 B+ 樹索引差別是什麼?你在設計索引是怎麼抉擇的?
  • B+ 樹可以進行範圍查詢,Hash 索引不能。
  • B+ 樹支援聯合索引的最左側原則,Hash 索引不支援。
  • B+ 樹支援 order by 排序,Hash 索引不支援。
  • Hash 索引在等值查詢上比 B+ 樹效率更高。
  • B+ 樹使用 like 進行模糊查詢的時候,like 後面(比如%開頭)的話可以起到優化的作用,Hash 索引根本無法進行模糊查詢。
什麼是最左字首原則?什麼是最左比對原則?

最左字首原則,就是最左優先,在建立多列索引時,要根據業務需求,where 子句中使用最頻繁的一列放在最左邊。

當我們建立一個組合索引的時候,如 (a1,a2,a3),相當于建立了(a1)、(a1,a2)和(a1,a2,a3)三個索引,這就是最左比對原則。

索引不适合哪些場景?
  • 資料量少的不适合加索引
  • 更新比較頻繁的也不适合加索引= 區分度低的字段不适合加索引(如性别)
索引有哪些優缺點?

(1) 優點:

  • 唯一索引可以保證資料庫表中每一行的資料的唯一性
  • 索引可以加快資料查詢速度,減少查詢時間

(2)缺點:

  • 建立索引和維護索引要耗費時間
  • 索引需要占實體空間,除了資料表占用資料空間之外,每一個索引還要占用一定的實體空間
  • 以表中的資料進行增、删、改的時候,索引也要動态的維護。

MySQL 遇到過死鎖問題嗎,你是如何解決的?

遇到過。我排查死鎖的一般步驟是醬紫的:

(1)檢視死鎖日志 show engine innodb status;(2)找出死鎖Sql

(3)分析sql加鎖情況

(4)模拟死鎖案發

(5)分析死鎖日志

(6)分析死鎖結果

說說資料庫的樂觀鎖和悲觀鎖是什麼以及它們的差別?

(1)悲觀鎖:

悲觀鎖她專一且缺乏安全感了,她的心隻屬于目前事務,每時每刻都擔心着它心愛的資料可能被别的事務修改,是以一個事務擁有(獲得)悲觀鎖後,其他任何事務都不能對資料進行修改啦,隻能等待鎖被釋放才可以執行。

(2)樂觀鎖:

樂觀鎖的“樂觀情緒”展現在,它認為資料的變動不會太頻繁。是以,它允許多個事務同時對資料進行變動。

實作方式:樂觀鎖一般會使用版本号機制或CAS算法實作。

MVCC 熟悉嗎,知道它的底層原理?

MVCC (Multiversion Concurrency Control),即多版本并發控制技術。

MVCC在MySQL InnoDB中的實作主要是為了提高資料庫并發性能,用更好的方式去處理讀-寫沖突,做到即使有讀寫沖突時,也能做到不加鎖,非阻塞并發讀。

事務

MySQL事務得四大特性以及實作原理
  • 原子性:事務作為一個整體被執行,包含在其中的對資料庫的操作要麼全部被執行,要麼都不執行。
  • 一緻性:指在事務開始之前和事務結束以後,資料不會被破壞,假如A賬戶給B賬戶轉10塊錢,不管成功與否,A和B的總金額是不變的。
  • 隔離性:多個事務并發通路時,事務之間是互相隔離的,即一個事務不影響其它事務運作效果。簡言之,就是事務之間是進水不犯河水的。
  • 持久性:表示事務完成以後,該事務對資料庫所作的操作更改,将持久地儲存在資料庫之中。
事務的隔離級别有哪些?MySQL的預設隔離級别是什麼?
  • 讀未送出(Read Uncommitted)
  • 讀已送出(Read Committed)
  • 可重複讀(Repeatable Read)
  • 串行化(Serializable)

Mysql預設的事務隔離級别是可重複讀(Repeatable Read)

什麼是幻讀,髒讀,不可重複讀呢?

事務A、B交替執行,事務A被事務B幹擾到了,因為事務A讀取到事務B未送出的資料,這就是髒讀。

在一個事務範圍内,兩個相同的查詢,讀取同一條記錄,卻傳回了不同的資料,這就是不可重複讀。

事務A查詢一個範圍的結果集,另一個并發事務B往這個範圍中插入/删除了資料,并靜悄悄地送出,然後事務A再次查詢相同的範圍,兩次讀取得到的結果集不一樣了,這就是幻讀。

實戰

MySQL資料庫cpu飙升的話,要怎麼處理呢?

排查過程:

(1)使用top 指令觀察,确定是mysqld導緻還是其他原因。(2)如果是mysqld導緻的,show processlist,檢視session情況,确定是不是有消耗資源的sql在運作。(3)找出消耗高的 sql,看看執行計劃是否準确, 索引是否缺失,資料量是否太大。

處理:

(1)kill 掉這些線程(同時觀察 cpu 使用率是否下降),(2)進行相應的調整(比如說加索引、改 sql、改記憶體參數)

(3)重新跑這些 SQL。

其他情況:

也有可能是每個 sql 消耗資源并不多,但是突然之間,有大量的 session 連進來導緻 cpu 飙升,這種情況就需要跟應用一起來分析為何連接配接數會激增,再做出相應的調整,比如說限制連接配接數等

MYSQL的主從延遲,你怎麼解決?

主從複制分了五個步驟進行:(圖檔來源于網絡)

快問快答,MySQL面試奪命20問
  • 步驟一:主庫的更新事件(update、insert、delete)被寫到binlog
  • 步驟二:從庫發起連接配接,連接配接到主庫。
  • 步驟三:此時主庫建立一個binlog dump thread,把binlog的内容發送到從庫。
  • 步驟四:從庫啟動之後,建立一個I/O線程,讀取主庫傳過來的binlog内容并寫入到relay log
  • 步驟五:還會建立一個SQL線程,從relay log裡面讀取内容,從Exec_Master_Log_Pos位置開始執行讀取到的更新事件,将更新内容寫入到slave的db

主從同步延遲的原因

一個伺服器開放N個連結給用戶端來連接配接的,這樣有會有大并發的更新操作, 但是從伺服器的裡面讀取binlog的線程僅有一個,當某個SQL在從伺服器上執行的時間稍長 或者由于某個SQL要進行鎖表就會導緻,主伺服器的SQL大量積壓,未被同步到從伺服器裡。這就導緻了主從不一緻, 也就是主從延遲。

主從同步延遲的解決辦法

  • 主伺服器要負責更新操作,對安全性的要求比從伺服器要高,是以有些設定參數可以修改,比如sync_binlog=1,innodb_flush_log_at_trx_commit = 1 之類的設定等。
  • 選擇更好的硬體裝置作為slave。
  • 把一台從伺服器當度作為備份使用, 而不提供查詢, 那邊他的負載下來了, 執行relay log 裡面的SQL效率自然就高了。
  • 增加從伺服器喽,這個目的還是分散讀的壓力,進而降低伺服器負載。
如果讓你做分庫與分表的設計,簡單說說你會怎麼做?

分庫分表方案:

  • 水準分庫:以字段為依據,按照一定政策(hash、range等),将一個庫中的資料拆分到多個庫中。
  • 水準分表:以字段為依據,按照一定政策(hash、range等),将一個表中的資料拆分到多個表中。
  • 垂直分庫:以表為依據,按照業務歸屬不同,将不同的表拆分到不同的庫中。
  • 垂直分表:以字段為依據,按照字段的活躍性,将表中字段拆到不同的表(主表和擴充表)中。

常用的分庫分表中間件:

  • sharding-jdbc
  • Mycat

分庫分表可能遇到的問題

  • 事務問題:需要用分布式事務啦
  • 跨節點Join的問題:解決這一問題可以分兩次查詢實作
  • 跨節點的count,order by,group by以及聚合函數問題:分别在各個節點上得到結果後在應用程式端進行合并。
  • 資料遷移,容量規劃,擴容等問題
  • ID問題:資料庫被切分後,不能再依賴資料庫自身的主鍵生成機制啦,最簡單可以考慮UUID
  • 跨分片的排序分頁問題