最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL常考八股面試題:日志、SQL?優(yōu)化、鎖、事務(wù)、MVCC

 更新時(shí)間:2026年05月27日 09:25:46   作者:huaixinsi  
MySQL作為目前最流行的關(guān)系型數(shù)據(jù)庫管理系統(tǒng)之一,往往是我們學(xué)習(xí)數(shù)據(jù)庫的首選,下面這篇文章主要介紹了MySQL常考八股面試題:日志、SQL?優(yōu)化、鎖、事務(wù)、MVCC的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

這篇文章按圖片里的分類整理 MySQL 面試高頻問題。寫法盡量通俗,重點(diǎn)放在面試常問、開發(fā)常用、容易踩坑的地方,不做過度源碼展開。

一、日志

1. MySQL 三大日志:redo log、undo log、binlog 各自作用?

MySQL 面試?yán)镒畛柕娜惾罩臼?redo logundo log、binlog

redo log 是 InnoDB 的重做日志,主要保證事務(wù)的持久性。事務(wù)提交后,即使數(shù)據(jù)庫突然宕機(jī),也可以通過 redo log 把已經(jīng)提交的數(shù)據(jù)恢復(fù)回來。

undo log 是回滾日志,主要保證事務(wù)原子性,也用于 MVCC。事務(wù)執(zhí)行過程中會(huì)記錄修改前的數(shù)據(jù),如果事務(wù)回滾,就可以根據(jù) undo log 恢復(fù)舊值。

binlog 是 MySQL Server 層的二進(jìn)制日志,主要用于主從復(fù)制、數(shù)據(jù)恢復(fù)和審計(jì)。它記錄的是數(shù)據(jù)庫發(fā)生了哪些邏輯變更。

一句話記憶:

  • redo log:保證崩潰恢復(fù),偏物理。
  • undo log:保證事務(wù)回滾和 MVCC,記錄舊版本。
  • binlog:保證復(fù)制和歸檔,偏邏輯。

2. redo log 為什么能保證事務(wù)崩潰恢復(fù)?WAL 機(jī)制是什么?

redo log 能保證崩潰恢復(fù),核心靠 WAL,也就是 Write Ahead Logging,先寫日志,再寫數(shù)據(jù)頁。

InnoDB 修改數(shù)據(jù)時(shí),不會(huì)每次都立刻把磁盤上的數(shù)據(jù)頁改掉,而是先修改內(nèi)存中的 Buffer Pool,同時(shí)記錄 redo log。事務(wù)提交時(shí),只要 redo log 持久化成功,就認(rèn)為事務(wù)提交成功。

如果數(shù)據(jù)庫宕機(jī),內(nèi)存里的臟頁可能還沒刷到磁盤,但 redo log 已經(jīng)在磁盤上。重啟后 InnoDB 會(huì)根據(jù) redo log 重放修改,把數(shù)據(jù)恢復(fù)到提交后的狀態(tài)。

通俗說:redo log 像快遞簽收記錄,貨物還沒完全入庫,但簽收記錄在,系統(tǒng)恢復(fù)后可以按記錄補(bǔ)齊。

3. binlog 是什么?statement、row、mixed 格式區(qū)別?

binlog 是 MySQL Server 層的二進(jìn)制日志,記錄數(shù)據(jù)庫變更,常用于主從復(fù)制和數(shù)據(jù)恢復(fù)。

它有三種常見格式:

statement:記錄 SQL 語句。優(yōu)點(diǎn)是日志量小,缺點(diǎn)是某些 SQL 在主從執(zhí)行結(jié)果可能不一致,比如 now()、uuid()、不確定順序的更新。

row:記錄每一行數(shù)據(jù)的變化。優(yōu)點(diǎn)是最準(zhǔn)確,主從一致性最好;缺點(diǎn)是日志量可能很大。

mixed:混合模式。MySQL 會(huì)根據(jù) SQL 是否安全,自動(dòng)選擇 statement 或 row。

生產(chǎn)環(huán)境更常用 row,因?yàn)閺?fù)制更可靠,也方便做數(shù)據(jù)訂正和恢復(fù)。

4. redo log 和 binlog 區(qū)別?

redo log 和 binlog 經(jīng)常一起問,因?yàn)樗鼈兌加涗浶薷模ㄎ煌耆煌?/p>

redo log 是 InnoDB 引擎層日志,binlog 是 MySQL Server 層日志。

redo log 主要用于崩潰恢復(fù),binlog 主要用于主從復(fù)制和數(shù)據(jù)恢復(fù)。

redo log 是循環(huán)寫,空間固定,會(huì)覆蓋舊日志;binlog 是追加寫,一個(gè)文件寫滿后切換到下一個(gè)。

redo log 記錄偏物理變化,比如某個(gè)頁做了什么修改;binlog 記錄偏邏輯變化,比如執(zhí)行了什么 SQL 或哪行變成什么樣。

一句話:redo log 管“宕機(jī)后自己怎么恢復(fù)”,binlog 管“別人怎么同步和回放”。

5. 事務(wù)提交時(shí) redo log、binlog 兩階段提交原理?

兩階段提交是為了保證 redo log 和 binlog 一致。

大致流程:

  1. InnoDB 寫 redo log,狀態(tài)為 prepare。
  2. MySQL Server 寫 binlog。
  3. InnoDB 把 redo log 改成 commit 狀態(tài)。

為什么要這樣?因?yàn)槭聞?wù)提交涉及兩個(gè)日志,如果只寫成功一個(gè)就宕機(jī),會(huì)出現(xiàn)主庫和從庫數(shù)據(jù)不一致。

恢復(fù)時(shí)會(huì)判斷:

  • redo log 有 prepare,binlog 也完整:提交事務(wù)。
  • redo log 有 prepare,binlog 不完整:回滾事務(wù)。

這樣可以保證主庫崩潰恢復(fù)結(jié)果和 binlog 復(fù)制結(jié)果一致。

二、SQL 優(yōu)化

1. 一條 SQL 執(zhí)行完整流程?

一條 SQL 大致會(huì)經(jīng)過這些步驟:

  1. 客戶端發(fā)送 SQL 到 MySQL Server。
  2. 連接器管理連接和權(quán)限。
  3. 解析器做詞法、語法分析。
  4. 預(yù)處理器檢查表、字段是否存在。
  5. 優(yōu)化器選擇執(zhí)行計(jì)劃,比如用哪個(gè)索引、表連接順序。
  6. 執(zhí)行器調(diào)用存儲(chǔ)引擎接口。
  7. 存儲(chǔ)引擎讀取或修改數(shù)據(jù)。
  8. 返回結(jié)果給客戶端。

如果是更新語句,還會(huì)涉及 undo log、redo log、binlog 等日志。

2. explain 執(zhí)行計(jì)劃每個(gè)字段含義?

explain 用來查看 SQL 執(zhí)行計(jì)劃,面試常問這些字段:

id:查詢執(zhí)行順序標(biāo)識(shí)。id 越大通常越先執(zhí)行;相同 id 從上往下執(zhí)行。

select_type:查詢類型,比如 SIMPLE、PRIMARY、SUBQUERY、DERIVED。

type:訪問類型,表示查表效率,優(yōu)化重點(diǎn)字段。

key:實(shí)際使用的索引。

rows:優(yōu)化器預(yù)估要掃描的行數(shù)。

Extra:額外信息,比如 Using index、Using where、Using filesort、Using temporary。

看 explain 時(shí),重點(diǎn)關(guān)注 typekey、rows、Extra。

3. type 執(zhí)行效率級(jí)別:all、index、range、ref、eq_ref、const、system

type 表示 MySQL 怎么訪問表,常見效率從差到好大概是:

ALL < index < range < ref < eq_ref < const < system
  • ALL:全表掃描,通常最差。
  • index:掃描整個(gè)索引樹,比全表掃描稍好,但仍然掃很多。
  • range:范圍掃描,比如 between>、in
  • ref:普通索引等值匹配,可能匹配多行。
  • eq_ref:唯一索引或主鍵關(guān)聯(lián)查詢,每次最多匹配一行。
  • const:主鍵或唯一索引等值查詢,結(jié)果最多一行。
  • system:表只有一行,是 const 的特殊情況。

實(shí)際優(yōu)化目標(biāo)一般是避免 ALL,盡量達(dá)到 range、ref 或更好。

4. 怎么看慢查詢?nèi)罩荆?/h3>

慢查詢?nèi)罩居糜谟涗泩?zhí)行時(shí)間超過閾值的 SQL。

常用參數(shù):

  • slow_query_log:是否開啟慢查詢?nèi)罩尽?/li>
  • long_query_time:超過多少秒算慢 SQL。
  • slow_query_log_file:慢查詢?nèi)罩疚募窂健?/li>

排查時(shí)重點(diǎn)看:

  • SQL 原文。
  • 執(zhí)行耗時(shí)。
  • 掃描行數(shù)。
  • 返回行數(shù)。
  • 是否走索引。

常用分析工具有 mysqldumpslowpt-query-digest。

5. 慢查詢優(yōu)化整體思路?

慢 SQL 優(yōu)化可以按這個(gè)順序來:

  1. 用慢查詢?nèi)罩径ㄎ粏栴} SQL。
  2. explain 看執(zhí)行計(jì)劃。
  3. 判斷是否走了合適索引。
  4. 檢查是否有回表、Using filesort、Using temporary。
  5. 優(yōu)化 SQL 寫法,減少掃描行數(shù)。
  6. 必要時(shí)調(diào)整索引、拆表、緩存或改業(yè)務(wù)方案。

核心原則:少掃行、少回表、少排序、少臨時(shí)表。

6. limit 分頁深偏移量怎么優(yōu)化?例如limit 1000000, 10

limit 1000000, 10 慢,是因?yàn)?MySQL 需要先掃描并丟棄前 1000000 行,再返回 10 行。

常見優(yōu)化方式:

第一種,基于上一頁最大 id 做游標(biāo)分頁:

select * from user
where id > 1000000
order by id
limit 10;

第二種,先用覆蓋索引查出 id,再回表:

select u.*
from user u
join (
    select id from user order by id limit 1000000, 10
) t on u.id = t.id;

第三種,產(chǎn)品層面避免跳到特別深的頁,比如搜索引擎通常只展示前幾十頁。

7. order by 排序原理,什么時(shí)候 Using filesort?怎么優(yōu)化?

order by 如果能直接利用索引順序,就不需要額外排序。

如果不能利用索引排序,MySQL 會(huì)使用 filesort。這里的 filesort 不一定真的落磁盤,它表示額外排序算法,數(shù)據(jù)大時(shí)可能用臨時(shí)文件。

常見觸發(fā)原因:

  • 排序字段沒有合適索引。
  • 聯(lián)合索引順序不符合最左前綴。
  • 排序方向混亂,索引無法完全利用。
  • where 條件和 order by 字段不匹配。

優(yōu)化方式:

  • where + order by 建合適聯(lián)合索引。
  • 盡量使用覆蓋索引。
  • 控制返回?cái)?shù)據(jù)量。
  • 避免對(duì)排序字段使用函數(shù)或表達(dá)式。

8. group by 原理與優(yōu)化思路?

group by 用于分組聚合。MySQL 執(zhí)行時(shí)通常需要按分組字段聚集數(shù)據(jù),可能用索引,也可能用臨時(shí)表和排序。

優(yōu)化思路:

  • 給分組字段建立索引。
  • where 先過濾,減少參與分組的數(shù)據(jù)量。
  • 只查詢必要字段。
  • 避免大結(jié)果集分組。
  • 能在業(yè)務(wù)或離線任務(wù)預(yù)聚合的,不要每次實(shí)時(shí)算大表。

如果 explain 里出現(xiàn) Using temporary、Using filesort,說明可能存在額外臨時(shí)表和排序成本。

9. join 連接原理:內(nèi)連接、左連接、右連接

join 本質(zhì)是把多張表按條件關(guān)聯(lián)起來。

內(nèi)連接 inner join:只返回兩邊都匹配的數(shù)據(jù)。

左連接 left join:返回左表全部數(shù)據(jù),右表匹配不到時(shí)右表字段為 null。

右連接 right join:返回右表全部數(shù)據(jù),左表匹配不到時(shí)左表字段為 null。

開發(fā)中更常用 inner joinleft join。右連接通??梢愿膶懗勺筮B接,保持閱讀習(xí)慣統(tǒng)一。

10. 大表 join 怎么優(yōu)化?

大表 join 優(yōu)化重點(diǎn)是減少驅(qū)動(dòng)表數(shù)據(jù)量,并讓被驅(qū)動(dòng)表能走索引。

常見做法:

  • 小表驅(qū)動(dòng)大表。
  • join 字段建立索引,類型保持一致。
  • 先 where 過濾,再 join。
  • 只查需要字段,避免 select *。
  • 大分頁、大排序、大分組盡量拆分。
  • 復(fù)雜場景可以用冗余字段、寬表、緩存、離線計(jì)算。

一句話:讓參與 join 的數(shù)據(jù)盡量少,讓匹配過程盡量走索引。

三、基礎(chǔ)概念

1. MySQL 存儲(chǔ)引擎有哪些?InnoDB、MyISAM 區(qū)別?

MySQL 常見存儲(chǔ)引擎有 InnoDB、MyISAM、Memory、Archive 等?,F(xiàn)在生產(chǎn)最常用的是 InnoDB。

InnoDB 支持事務(wù)、行級(jí)鎖、外鍵、崩潰恢復(fù),適合高并發(fā)和事務(wù)場景。

MyISAM 不支持事務(wù),不支持行鎖,主要是表級(jí)鎖,崩潰恢復(fù)能力弱,但結(jié)構(gòu)簡單,早期讀多寫少場景用得較多。

現(xiàn)在默認(rèn)優(yōu)先選擇 InnoDB。

2. InnoDB 相比 MyISAM 優(yōu)勢(shì)在哪?

InnoDB 的優(yōu)勢(shì)主要有:

  • 支持事務(wù),滿足 ACID。
  • 支持行級(jí)鎖,并發(fā)寫能力更好。
  • 支持崩潰恢復(fù),可靠性更高。
  • 支持 MVCC,提高讀寫并發(fā)。
  • 支持外鍵。

面試?yán)锟梢灾苯诱f:InnoDB 更適合現(xiàn)代業(yè)務(wù)系統(tǒng),尤其是高并發(fā)、強(qiáng)一致、需要事務(wù)的場景。

3. 什么是事務(wù)?事務(wù)四大特性 ACID 分別是什么?

事務(wù)是一組操作的集合,要么全部成功,要么全部失敗。

ACID 分別是:

A Atomicity 原子性:事務(wù)內(nèi)操作要么全成功,要么全失敗。主要靠 undo log。

C Consistency 一致性:事務(wù)執(zhí)行前后,數(shù)據(jù)從一個(gè)一致狀態(tài)變成另一個(gè)一致狀態(tài)。

I Isolation 隔離性:多個(gè)事務(wù)并發(fā)執(zhí)行時(shí),彼此影響受隔離級(jí)別控制。

D Durability 持久性:事務(wù)提交后數(shù)據(jù)不會(huì)丟。主要靠 redo log。

4. 數(shù)據(jù)庫三范式是什么?日常開發(fā)一定要嚴(yán)格遵守嗎?

第一范式:字段不可再分,保證原子性。

第二范式:非主鍵字段必須完全依賴主鍵,避免部分依賴。

第三范式:非主鍵字段不能依賴其他非主鍵字段,避免傳遞依賴。

日常開發(fā)不一定死守三范式。范式能減少冗余、提高一致性,但有時(shí)為了查詢性能,會(huì)適當(dāng)反范式,比如冗余用戶名、訂單快照、統(tǒng)計(jì)字段。

原則是:核心數(shù)據(jù)保證一致,讀多性能瓶頸場景可以有控制地冗余。

5. 執(zhí)行一條 SQL 語句,期間都發(fā)生了哪些事情?

以更新語句為例:

  1. 客戶端發(fā)送 SQL。
  2. Server 層解析、優(yōu)化、生成執(zhí)行計(jì)劃。
  3. 執(zhí)行器調(diào)用 InnoDB。
  4. InnoDB 找到數(shù)據(jù)頁,加載到 Buffer Pool。
  5. 記錄 undo log,便于回滾。
  6. 修改內(nèi)存頁,產(chǎn)生臟頁。
  7. 寫 redo log prepare。
  8. Server 層寫 binlog。
  9. redo log commit。
  10. 后臺(tái)線程擇機(jī)把臟頁刷盤。

查詢語句則主要涉及解析、優(yōu)化、執(zhí)行、走索引、回表、返回結(jié)果。

四、鎖

1. InnoDB 有哪些鎖?行鎖、表鎖、意向鎖

InnoDB 常見鎖包括:

  • 表鎖:鎖整張表。
  • 行鎖:鎖某些記錄,粒度小,并發(fā)度高。
  • 意向鎖:表級(jí)鎖,用來表示事務(wù)接下來想鎖某些行。
  • 記錄鎖:鎖具體索引記錄。
  • 間隙鎖:鎖兩個(gè)索引記錄之間的間隙。
  • 臨鍵鎖:記錄鎖 + 間隙鎖。

InnoDB 的行鎖是加在索引上的,如果查詢條件沒有走索引,可能導(dǎo)致鎖范圍變大。

2. 行鎖什么時(shí)候變表鎖?

嚴(yán)格說,InnoDB 行鎖不會(huì)真的“升級(jí)”為表鎖;但如果 SQL 沒有走索引,InnoDB 可能掃描很多行并對(duì)大量記錄加鎖,看起來像鎖表。

常見原因:

  • where 條件沒有索引。
  • 索引失效。
  • 字段類型不一致導(dǎo)致隱式轉(zhuǎn)換。
  • 范圍條件過大。

所以更新和刪除時(shí)一定要確認(rèn)條件走索引,尤其是大表。

3. 記錄鎖、間隙鎖、臨鍵鎖分別是什么?

記錄鎖 Record Lock:鎖住某一條索引記錄。

間隙鎖 Gap Lock:鎖住索引記錄之間的間隙,不鎖具體記錄,主要防止幻讀。

臨鍵鎖 Next-Key Lock:記錄鎖 + 間隙鎖,既鎖記錄,也鎖記錄前面的間隙。

例如索引里有 10 和 20,間隙鎖可能鎖住 (10, 20) 這個(gè)范圍,防止其他事務(wù)插入 15。

4. 臨鍵鎖怎么解決幻讀?

幻讀是同一個(gè)事務(wù)內(nèi),兩次范圍查詢結(jié)果條數(shù)不一致,比如第一次查沒有某條記錄,第二次查突然出現(xiàn)了。

在可重復(fù)讀隔離級(jí)別下,InnoDB 對(duì)范圍查詢加臨鍵鎖,鎖住已有記錄和記錄之間的間隙。這樣其他事務(wù)就不能在這個(gè)范圍里插入新記錄。

所以臨鍵鎖通過“鎖記錄 + 鎖間隙”防止范圍內(nèi)新增數(shù)據(jù),從而解決當(dāng)前讀下的幻讀問題。

5. 什么是死鎖?產(chǎn)生條件、怎么排查和避免死鎖?

死鎖是多個(gè)事務(wù)互相等待對(duì)方持有的鎖,導(dǎo)致都無法繼續(xù)。

產(chǎn)生條件:

  • 互斥。
  • 持有并等待。
  • 不可剝奪。
  • 循環(huán)等待。

排查方式:

  • 使用 show engine innodb status 查看最近一次死鎖信息。
  • 查看事務(wù)持有什么鎖、等待什么鎖。
  • 結(jié)合慢 SQL、業(yè)務(wù)日志定位 SQL 順序。

避免方式:

  • 統(tǒng)一加鎖順序。
  • 事務(wù)盡量短。
  • where 條件走索引。
  • 避免大范圍更新。
  • 必要時(shí)使用重試機(jī)制。

五、事務(wù)(超級(jí)高頻)

1. MySQL 四大事務(wù)隔離級(jí)別分別是什么?

MySQL 標(biāo)準(zhǔn)隔離級(jí)別有四種:

  • 讀未提交 Read Uncommitted。
  • 讀已提交 Read Committed。
  • 可重復(fù)讀 Repeatable Read。
  • 串行化 Serializable。

隔離級(jí)別越高,并發(fā)能力通常越低,一致性約束越強(qiáng)。

2. 臟讀、不可重復(fù)讀、幻讀分別是什么?

臟讀:讀到了其他事務(wù)還沒提交的數(shù)據(jù)。如果對(duì)方回滾,你讀到的就是臟數(shù)據(jù)。

不可重復(fù)讀:同一個(gè)事務(wù)內(nèi),兩次讀取同一行數(shù)據(jù),結(jié)果不一樣。通常是其他事務(wù)提交了修改。

幻讀:同一個(gè)事務(wù)內(nèi),兩次范圍查詢,結(jié)果集條數(shù)不一樣。通常是其他事務(wù)插入或刪除了符合條件的數(shù)據(jù)。

簡單記:臟讀讀到未提交,不可重復(fù)讀是同一行變了,幻讀是結(jié)果集行數(shù)變了。

3. 四大隔離級(jí)別分別能解決哪些問題?

讀未提交:什么都解決不了,可能臟讀、不可重復(fù)讀、幻讀。

讀已提交:解決臟讀,但可能不可重復(fù)讀和幻讀。

可重復(fù)讀:解決臟讀、不可重復(fù)讀。InnoDB 通過 MVCC 和臨鍵鎖在很多場景下也解決幻讀。

串行化:基本都能解決,但并發(fā)性能最低。

生產(chǎn)中 MySQL InnoDB 默認(rèn)是可重復(fù)讀。

4. InnoDB 默認(rèn)隔離級(jí)別是什么?

InnoDB 默認(rèn)隔離級(jí)別是 Repeatable Read,也就是可重復(fù)讀。

它通過 MVCC 保證普通快照讀的可重復(fù)讀,通過 next-key lock 處理當(dāng)前讀下的幻讀問題。

5. 什么是幻讀?怎么解決幻讀?

幻讀指一個(gè)事務(wù)內(nèi)兩次范圍查詢,第二次出現(xiàn)了第一次沒有的記錄,像“幻影”一樣。

解決方式:

  • 串行化隔離級(jí)別,直接強(qiáng)約束并發(fā)。
  • InnoDB 可重復(fù)讀下,普通快照讀通過 Read View 避免幻讀。
  • 當(dāng)前讀通過 next-key lock 鎖住范圍,阻止其他事務(wù)插入。

注意:MVCC 主要解決快照讀的一致性,臨鍵鎖主要解決當(dāng)前讀的幻讀。

6. 事務(wù)的實(shí)現(xiàn)原理:MVCC 是什么?

事務(wù)能力不是一個(gè)單獨(dú)機(jī)制完成的,而是多個(gè)機(jī)制配合:

  • 原子性靠 undo log。
  • 持久性靠 redo log。
  • 隔離性靠鎖和 MVCC。
  • 一致性由業(yè)務(wù)約束、數(shù)據(jù)庫約束和上述機(jī)制共同保證。

MVCC 是多版本并發(fā)控制。它讓讀操作可以讀到某個(gè)時(shí)間點(diǎn)的數(shù)據(jù)版本,而不是總被寫操作阻塞。

通俗說:數(shù)據(jù)被修改后,舊版本不會(huì)立刻消失,讀事務(wù)可以根據(jù)規(guī)則找到自己應(yīng)該看到的版本。

7. 可重復(fù)讀隔離級(jí)別,完全解決幻讀了嗎?

要分情況說。

對(duì)于普通 select 快照讀,可重復(fù)讀通過 MVCC 的 Read View 能保證同一事務(wù)內(nèi)查詢結(jié)果一致,基本避免幻讀。

對(duì)于 select ... for update、update、delete 這類當(dāng)前讀,InnoDB 通過 next-key lock 鎖范圍,防止其他事務(wù)插入,從而避免幻讀。

但如果混用快照讀和當(dāng)前讀,可能看到不一樣的結(jié)果,這是面試?yán)锏募臃贮c(diǎn)。

六、MVCC

1. MVCC 底層原理是什么?

MVCC 全稱 Multi-Version Concurrency Control,多版本并發(fā)控制。

InnoDB 每行記錄都有隱藏字段,配合 undo log 保存歷史版本,再通過 Read View 判斷當(dāng)前事務(wù)能看到哪個(gè)版本。

它的核心目標(biāo)是提高讀寫并發(fā):讀不阻塞寫,寫不阻塞普通讀。

2. 什么是快照讀、當(dāng)前讀?舉例說明

快照讀讀取的是某個(gè)時(shí)間點(diǎn)的數(shù)據(jù)版本,不加鎖。

普通 select 通常是快照讀:

select * from user where id = 1;

當(dāng)前讀讀取的是最新數(shù)據(jù),并且通常要加鎖。

常見當(dāng)前讀:

select * from user where id = 1 for update;
update user set name = 'Tom' where id = 1;
delete from user where id = 1;

快照讀看歷史版本,當(dāng)前讀看最新版本。

3. 隱式字段 DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID 作用?

InnoDB 行記錄里有幾個(gè)隱藏字段:

DB_TRX_ID:最近一次修改這行記錄的事務(wù) id。

DB_ROLL_PTR:回滾指針,指向 undo log 中的舊版本。

DB_ROW_ID:如果表沒有主鍵和唯一非空索引,InnoDB 會(huì)生成隱藏行 id。

MVCC 主要依賴 DB_TRX_IDDB_ROLL_PTR 找到可見版本。

4. undo log 日志作用、版本鏈?zhǔn)鞘裁矗?/h3>

undo log 記錄數(shù)據(jù)修改前的舊值,用于事務(wù)回滾和 MVCC。

當(dāng)一行數(shù)據(jù)被多次修改時(shí),每次修改都會(huì)產(chǎn)生 undo log,記錄之間通過回滾指針串起來,就形成版本鏈。

查詢時(shí),如果當(dāng)前版本對(duì)事務(wù)不可見,InnoDB 會(huì)沿著版本鏈往前找,直到找到一個(gè)可見版本,或者找不到。

5. Read View 視圖四個(gè)字段作用、可見性規(guī)則?

Read View 是 MVCC 判斷版本是否可見的核心。

常見字段:

  • m_ids:創(chuàng)建 Read View 時(shí),系統(tǒng)中活躍事務(wù) id 列表。
  • min_trx_id:活躍事務(wù)中最小 id。
  • max_trx_id:下一個(gè)將要分配的事務(wù) id。
  • creator_trx_id:創(chuàng)建這個(gè) Read View 的事務(wù) id。

可見性規(guī)則簡化理解:

  • 如果版本的事務(wù) id 小于 min_trx_id,說明早就提交了,可見。
  • 如果版本的事務(wù) id 大于等于 max_trx_id,說明是之后才出現(xiàn)的,不可見。
  • 如果事務(wù) id 在 m_ids 里,說明當(dāng)時(shí)還沒提交,不可見。
  • 如果事務(wù) id 不在 m_ids 里,說明已經(jīng)提交,可見。

6. MVCC 怎么實(shí)現(xiàn)可重復(fù)讀、讀已提交?

讀已提交 RC:每次執(zhí)行普通 select 都會(huì)生成新的 Read View。所以同一個(gè)事務(wù)里,第二次查詢能看到其他事務(wù)已經(jīng)提交的數(shù)據(jù)。

可重復(fù)讀 RR:事務(wù)中第一次普通 select 時(shí)生成 Read View,后續(xù)普通 select 復(fù)用這個(gè) Read View。所以同一個(gè)事務(wù)里多次讀取結(jié)果一致。

區(qū)別就在于 Read View 的創(chuàng)建時(shí)機(jī)。

七、索引

1. InnoDB 索引結(jié)構(gòu)為什么選 B+ 樹,不選二叉樹、紅黑樹、B 樹?

數(shù)據(jù)庫索引存儲(chǔ)在磁盤上,核心目標(biāo)是減少磁盤 IO。

二叉樹和紅黑樹高度相對(duì)較高,數(shù)據(jù)量大時(shí)查找層數(shù)多,磁盤 IO 多。

B 樹每個(gè)節(jié)點(diǎn)既存 key 也存數(shù)據(jù),單頁能放的 key 數(shù)量相對(duì)少,樹可能更高。

B+ 樹非葉子節(jié)點(diǎn)只存 key 和指針,葉子節(jié)點(diǎn)存完整數(shù)據(jù)或主鍵,單頁能放更多 key,樹更矮,IO 更少。葉子節(jié)點(diǎn)還用鏈表連接,范圍查詢更方便。

所以 InnoDB 選擇 B+ 樹是為了降低 IO、提高范圍查詢效率。

2. B+ 樹和 B 樹的區(qū)別?

B 樹的每個(gè)節(jié)點(diǎn)都可能存數(shù)據(jù)。

B+ 樹只有葉子節(jié)點(diǎn)存數(shù)據(jù),非葉子節(jié)點(diǎn)只做索引導(dǎo)航。

B+ 樹葉子節(jié)點(diǎn)之間有鏈表,范圍查詢更快。

B+ 樹單個(gè)非葉子節(jié)點(diǎn)能存更多 key,樹更矮,磁盤 IO 更少。

3. 聚簇索引和非聚簇索引(二級(jí)索引)區(qū)別?

聚簇索引的葉子節(jié)點(diǎn)存整行數(shù)據(jù)。在 InnoDB 中,主鍵索引就是聚簇索引。

非聚簇索引,也叫二級(jí)索引,葉子節(jié)點(diǎn)存的是索引字段和主鍵值。

通過二級(jí)索引查到主鍵后,如果還需要其他字段,就要再根據(jù)主鍵回到聚簇索引查整行,這就是回表。

4. 主鍵索引、唯一索引、普通索引、聯(lián)合索引區(qū)別?

主鍵索引:唯一且不能為空,一張表只能有一個(gè)主鍵。

唯一索引:值不能重復(fù),但通常允許 null,具體行為和數(shù)據(jù)庫規(guī)則有關(guān)。

普通索引:沒有唯一性限制,只提升查詢效率。

聯(lián)合索引:多個(gè)字段組合成一個(gè)索引,比如 (a, b, c),使用時(shí)要遵守最左前綴原則。

5. 什么是回表查詢?怎么避免回表?

回表是指通過二級(jí)索引查到主鍵后,再根據(jù)主鍵去聚簇索引查整行數(shù)據(jù)。

例如有索引 (name)

select age from user where name = 'Tom';

如果 age 不在索引里,就需要回表。

避免回表的方式是使用覆蓋索引,把查詢需要的字段都放進(jìn)索引:

create index idx_name_age on user(name, age);

6. 覆蓋索引是什么?使用場景?

覆蓋索引是指查詢需要的字段都能從索引里拿到,不需要回表。

例如聯(lián)合索引 (name, age)

select name, age from user where name = 'Tom';

這種情況下只查索引就夠了。

覆蓋索引適合高頻查詢、列表頁、分頁查詢等場景,可以減少回表 IO。

7. 最左前綴原則原理,為什么要遵守?

聯(lián)合索引按字段順序排序,比如 (a, b, c),索引先按 a 排,再按 b 排,最后按 c 排。

所以查詢必須從最左邊字段開始連續(xù)使用,才能充分利用索引。

可以走索引的例子:

where a = 1
where a = 1 and b = 2
where a = 1 and b = 2 and c = 3

不符合的例子:

where b = 2
where c = 3

因?yàn)槿鄙僮钭笞侄?a,索引整體順序用不上。

8. 索引下推原理和作用?

索引下推 Index Condition Pushdown,簡稱 ICP,是 MySQL 的一種優(yōu)化。

沒有索引下推時(shí),存儲(chǔ)引擎根據(jù)索引找到記錄后,可能先回表,再由 Server 層判斷其他條件。

有索引下推時(shí),能在存儲(chǔ)引擎層先用索引里的字段過濾一部分?jǐn)?shù)據(jù),減少回表次數(shù)。

典型場景是聯(lián)合索引中部分字段可以用于過濾,但不能完全用于定位。

9. 什么是索引失效?哪些情況會(huì)導(dǎo)致索引失效?

索引失效是指 SQL 雖然有索引,但優(yōu)化器沒有使用,或者只能使用一部分。

常見原因:

  • 對(duì)索引列使用函數(shù)或表達(dá)式。
  • 字段類型不一致導(dǎo)致隱式轉(zhuǎn)換。
  • like '%xxx' 前綴模糊。
  • 聯(lián)合索引不滿足最左前綴。
  • 使用 or 且部分條件沒有索引。
  • 范圍查詢后面的聯(lián)合索引字段無法繼續(xù)有序利用。
  • 數(shù)據(jù)量太小或優(yōu)化器判斷全表掃描更劃算。

優(yōu)化時(shí)不要只看“建沒建索引”,要看 explain 里實(shí)際有沒有用。

10. 模糊查詢like '%xxx'、like 'xxx%'哪個(gè)走索引?

like 'xxx%' 可以走索引,因?yàn)榍熬Y確定,B+ 樹可以按范圍查。

like '%xxx' 一般不能走普通 B+ 樹索引,因?yàn)殚_頭不確定,無法從索引樹定位范圍。

如果必須支持任意位置模糊搜索,可以考慮全文索引、搜索引擎,或者業(yè)務(wù)側(cè)倒排索引。

11. 字段類型隱式轉(zhuǎn)換為什么會(huì)導(dǎo)致索引失效?

如果字段類型和查詢條件類型不一致,MySQL 可能對(duì)字段做隱式轉(zhuǎn)換。

例如手機(jī)號(hào)字段是 varchar,卻這樣查:

where phone = 13800138000

MySQL 可能把 phone 轉(zhuǎn)成數(shù)字比較,相當(dāng)于對(duì)索引列做函數(shù)處理,索引就可能失效。

正確寫法:

where phone = '13800138000'

12. 為什么不建議用select *?

不建議 select * 的原因:

  • 查出不需要的字段,增加網(wǎng)絡(luò)和內(nèi)存開銷。
  • 更容易回表,無法利用覆蓋索引。
  • 表結(jié)構(gòu)變更時(shí),結(jié)果字段不穩(wěn)定。
  • 大字段如 text、blob 會(huì)拖慢查詢。

生產(chǎn)建議明確寫出需要的字段。

13. 聯(lián)合索引創(chuàng)建順序原則:區(qū)分度高、長度小、經(jīng)常查詢

聯(lián)合索引字段順序一般考慮:

  • 經(jīng)常用于查詢條件的字段靠前。
  • 區(qū)分度高的字段優(yōu)先。
  • 字段長度小的優(yōu)先,索引更緊湊。
  • 等值查詢字段通常放前面,范圍查詢字段放后面。
  • 還要兼顧 order by、group by。

沒有絕對(duì)公式,要結(jié)合真實(shí) SQL 和 explain 判斷。

14. 什么時(shí)候不適合建索引?

這些場景不太適合建索引:

  • 表數(shù)據(jù)量很小。
  • 字段區(qū)分度很低,比如性別、狀態(tài)值很少。
  • 字段很少用于查詢條件。
  • 寫入非常頻繁,索引會(huì)增加維護(hù)成本。
  • 大字段不適合直接建普通索引。
  • 已有聯(lián)合索引可以覆蓋,不需要重復(fù)建單列索引。

索引不是越多越好。它能加快查詢,但會(huì)拖慢寫入,并占用磁盤空間。

八、面試回答小抄

  • redo log 保證崩潰恢復(fù),undo log 支持回滾和 MVCC,binlog 用于復(fù)制和歸檔。
  • WAL 是先寫日志再寫數(shù)據(jù)頁,保證宕機(jī)后能恢復(fù)。
  • 兩階段提交解決 redo log 和 binlog 一致性問題。
  • explain 重點(diǎn)看 type、key、rows、Extra。
  • 慢 SQL 優(yōu)化核心是少掃行、少回表、少排序、少臨時(shí)表。
  • InnoDB 默認(rèn)隔離級(jí)別是可重復(fù)讀。
  • MVCC 依賴隱藏字段、undo log 版本鏈和 Read View。
  • 快照讀讀歷史版本,當(dāng)前讀讀最新版本并加鎖。
  • InnoDB 索引用 B+ 樹,是為了降低 IO 和優(yōu)化范圍查詢。
  • 聯(lián)合索引要遵守最左前綴原則。
  • like 'xxx%' 通??勺咚饕?code>like '%xxx' 通常不走普通索引。

總結(jié)

MySQL 面試題看起來分散,其實(shí)主線很清楚:

  • 日志:redo、undo、binlog 分別解決恢復(fù)、回滾、復(fù)制。
  • SQL 優(yōu)化:先定位慢 SQL,再看執(zhí)行計(jì)劃,最后減少掃描和回表。
  • 鎖:理解行鎖、間隙鎖、臨鍵鎖,以及死鎖排查。
  • 事務(wù):抓住 ACID、隔離級(jí)別、臟讀、不可重復(fù)讀、幻讀。
  • MVCC:抓住隱藏字段、undo 版本鏈、Read View。
  • 索引:抓住 B+ 樹、聚簇索引、回表、覆蓋索引、最左前綴。

面試回答時(shí)建議先說結(jié)論,再講原理,最后補(bǔ)一句實(shí)際開發(fā)中的坑點(diǎn),這樣比單純背概念更容易拿分。

到此這篇關(guān)于MySQL??及斯擅嬖囶}:日志、SQL 優(yōu)化、鎖、事務(wù)、MVCC的文章就介紹到這了,更多相關(guān)mysql??济嬖囶}內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 優(yōu)化mysql數(shù)據(jù)庫的經(jīng)驗(yàn)總結(jié)

    優(yōu)化mysql數(shù)據(jù)庫的經(jīng)驗(yàn)總結(jié)

    本篇文章是對(duì)優(yōu)化mysql數(shù)據(jù)庫的經(jīng)驗(yàn)進(jìn)行了詳細(xì)的總結(jié)介紹,需要的朋友參考下
    2013-06-06
  • Mysql中基本語句優(yōu)化的十個(gè)原則小結(jié)

    Mysql中基本語句優(yōu)化的十個(gè)原則小結(jié)

    這篇文章主要給大家總結(jié)介紹了Mysql中基本語句優(yōu)化的十個(gè)原則,通過學(xué)習(xí)與記住它們,在構(gòu)造sql時(shí)可以養(yǎng)成良好的習(xí)慣,文中介紹的相對(duì)比較詳細(xì)與簡單明了,需要的朋友們可以參考借鑒,下面來一起看看吧。
    2017-06-06
  • MySQL存儲(chǔ)引擎 InnoDB與MyISAM的區(qū)別

    MySQL存儲(chǔ)引擎 InnoDB與MyISAM的區(qū)別

    InnoDB和MyISAM是許多人在使用MySQL時(shí)最常用的兩個(gè)表類型,這兩個(gè)表類型各有優(yōu)劣,視具體應(yīng)用而定。
    2014-03-03
  • mysql實(shí)現(xiàn)定時(shí)備份的詳細(xì)圖文教程

    mysql實(shí)現(xiàn)定時(shí)備份的詳細(xì)圖文教程

    這篇文章主要給大家介紹了關(guān)于mysql實(shí)現(xiàn)定時(shí)備份的詳細(xì)圖文教程,我們都知道數(shù)據(jù)是無價(jià),如果不對(duì)數(shù)據(jù)進(jìn)行備份,相當(dāng)是讓數(shù)據(jù)在裸跑,一旦服務(wù)器出問題,只有哭的份了,需要的朋友可以參考下
    2023-07-07
  • 深入理解MySQL主從復(fù)制線程狀態(tài)轉(zhuǎn)變

    深入理解MySQL主從復(fù)制線程狀態(tài)轉(zhuǎn)變

    這篇文章主要給大家介紹了關(guān)于MySQL主從復(fù)制線程狀態(tài)轉(zhuǎn)變的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • mysql tmp_table_size和max_heap_table_size大小配置

    mysql tmp_table_size和max_heap_table_size大小配置

    這篇文章主要介紹了mysql tmp_table_size和max_heap_table_size大小配置,需要的朋友可以參考下
    2016-05-05
  • CentOS 6.5 i386 安裝MySQL 5.7.18詳細(xì)教程

    CentOS 6.5 i386 安裝MySQL 5.7.18詳細(xì)教程

    這篇文章主要介紹了CentOS 6.5 i386 安裝MySQL 5.7.18詳細(xì)教程,需要的朋友可以參考下
    2017-04-04
  • MySQL 修改數(shù)據(jù)庫名稱的一個(gè)新奇方法

    MySQL 修改數(shù)據(jù)庫名稱的一個(gè)新奇方法

    這篇文章主要介紹了MySQL 修改數(shù)據(jù)庫名稱的一個(gè)新奇方法,MySQL 修改數(shù)據(jù)庫名的一個(gè)變通方法,需要的朋友可以參考下
    2014-07-07
  • mysql性能優(yōu)化之索引優(yōu)化

    mysql性能優(yōu)化之索引優(yōu)化

    我們首先討論索引,因?yàn)樗羌涌觳樵兊淖钪匾墓ぞ?。?dāng)然還有其他加快查詢的技術(shù),但是最有效的莫過于恰當(dāng)?shù)厥褂盟饕恕O旅嫖覀兙蛠斫榻B索引是什么、它怎樣改善查詢性能、索引在什么情況下可能會(huì)降低性能,以及怎樣為表選擇索引。
    2015-12-12
  • mysql workbench 設(shè)置外鍵的方法實(shí)現(xiàn)

    mysql workbench 設(shè)置外鍵的方法實(shí)現(xiàn)

    在MySQL Workbench中設(shè)置外鍵屬性是非常方便的,本文就來介紹一下mysql workbench 設(shè)置外鍵的方法實(shí)現(xiàn),具有一定能的參考價(jià)值,感興趣的可以了解一下
    2024-01-01

最新評(píng)論

文山县| 和田县| 明水县| 灵武市| 疏勒县| 南涧| 望奎县| 武义县| 仪征市| 体育| 沐川县| 高青县| 蒲城县| 靖江市| 桐梓县| 霍林郭勒市| 佛学| 阿坝县| 北宁市| 江口县| 松江区| 江源县| 内黄县| 旌德县| 上犹县| 弋阳县| 丹江口市| 霸州市| 临夏市| 上思县| 张家界市| 石棉县| 喜德县| 云阳县| 仙桃市| 宁都县| 衡水市| 昭通市| 庆云县| 油尖旺区| 宣城市|