首页
/
每日頭條
/
職場
/
阿裡面試題mysql優化
阿裡面試題mysql優化
更新时间:2024-04-29 06:02:43

作者:公衆号非科班的科班

前言

迎面走來了一個風塵仆仆的身穿格子衫的男子,手裡拿着一個MacBook Pro,看着那稀少的發量,和那從容淡定的眼神。

我心裡一顫,我去,這是架構師,架構師來面我技術面,我心裡頓時不淡定了,表面很穩實則心裡慌的一批。

果然,他手裡拿着我的簡曆,快速的掃了一下,然後用眼角餘光看了一下我,上來就開問。

Mysql事務簡介

「面試官:」 看你簡曆上說精通Mysql優化方法,你先來說說你對Mysql的事務的了解吧。

我心裡喜了一下,這個簡單啊,哥我可是北大(背大)的,在來面試之前,早就有準備的,二話不說,上去就是背。

「我:」 好的,數據庫的事務是指一組sql語句組成的數據庫邏輯處理單元,在這組的sql操作中,要麼全部執行成功,要麼全部執行失敗。

「我:」 這裡的一組sql操作,舉個簡單又經典的例子就是轉賬了,事務A中要進行轉賬,那麼轉出的賬号要扣錢,轉入的賬号要加錢,這兩個操作都必須同時執行成功,為了确保數據的一緻性。

「面試官:」 剛才你提到了數據一緻性,你知道事務的特性嗎?說說你的理解。

ACID簡介

「我:」 在Mysql中事務的四大特性主要包含:「原子性(Atomicity)」「一緻性(Consistent)」「隔離性(Isalotion)」「持久性(Durable)」,簡稱為ACID。

「我:」 原子性是指事務的原子性操作,對數據的修改要麼全部執行成功,要麼全部失敗,實現事務的原子性,是基于日志的Redo/Undo機制。

「我:」 一緻性是指執行事務前後的狀态要一緻,可以理解為數據一緻性。隔離性側重指事務之間相互隔離,不受影響,這個與事務設置的隔離級别有密切的關系。

「我:」 持久性則是指在一個事務提交後,這個事務的狀态會被持久化到數據庫中,也就是事務提交,對數據的新增、更新将會持久化到書庫中。

「我:」 在我的理解中,原子性、隔離性、持久性都是為了保障一緻性而存在的,一緻性也是最終的目的。

心裡暗自歡喜,背完了,平時背的多,面試就會說,幸好難不倒我。

ACID原理

「面試官:」 剛才你說原子性是基于日志的Redo/Undo機制,你能說一說Redo/Undo機制嗎?

啊哈?我都說了什麼,不小心給自己埋了一顆大雷。不慌,哥腦子裡還有貨,假裝若有所思的停了幾十秒,接着背。

「我:」 Redo/Undo機制比較簡單,它們将所有對數據的更新操作都寫到日志中。

「我:」 Redo log用來記錄某數據塊被修改後的值,可以用來恢複未寫入 data file 的已成功事務更新的數據;Undo log是用來記錄數據更新前的值,保證數據更新失敗能夠回滾。

「我:」 假如數據庫在執行的過程中,不小心崩了,可以通過該日志的方式,回滾之前已經執行成功的操作,實現事務的一緻性。

「面試官:」 可以舉一個場景,說一下具體的實現流程嗎?

「我:」 可以的,假如某個時刻數據庫崩潰,在崩潰之前有事務A和事務B在執行,事務A已經提交,而事務B還未提交。當數據庫重啟進行 crash-recovery 時,就會通過Redo log将已經提交事務的更改寫到數據文件,而還沒有提交的就通過Undo log進行roll back。

事務隔離級别

「面試官:」 之前你還提到事務的隔離級别,你能說一說嗎?

「我:」 可以的,在Mysql中事務的隔離級别分為四大等級,「讀未提交(READ UNcommitTED)、讀提交 (READ COMMITTED)、可重複讀 (REPEATABLE READ)、串行化 (SERIALIZABLE)」

「我:」 讀未提交會讀到另一個事務的未提交的數據,産生髒讀問題,讀提交則解決了髒讀的,出現了不可重複讀,即在一個事務任意時刻讀到的數據可能不一樣,可能會受到其它事務對數據修改提交後的影響,一般是對于update的操作。

「我:」 可重複讀解決了之前不可重複讀和髒讀的問題,但是又帶來了幻讀的問題,幻讀一般是針對inser操作。

「我:」 例如:第一個事務查詢一個User表id=100發現不存在該數據行,這時第二個事務又進來了,新增了一條id=100的數據行并且提交了事務。

「我:」 這時第一個事務新增一條id=100的數據行會報主鍵沖突,第一個事務再select一下,發現id=100數據行已經存在,這就是幻讀。

「面試官:」 小夥子你能演示一下嗎?我不太會你能教教我嗎?我電腦在這裡,你演示我看一看。

男人的嘴騙人的鬼,我信你個鬼,你這糟老頭子壞得很,出來裝X總是要還的,隻能默默含淚把它敲完。

「我:」 首先創建一個User表,最為一個測試表,測試表裡面有三個字段,并插入兩條測試數據。

CREATE TABLE User ( id INT(11) NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20), age INT DEFAULT 0 ) ENGINE=InnoDB DEFAULT CHARSET=gb2312; 複制代碼INSERT INTO user複制代碼 VALUES (1, 'zhangsan', 23); INSERT INTO user複制代碼 VALUES (2, 'lisi', 20);

「我:」 在Mysql中可以先查詢一下他的默認隔離級别,可以看出Mysql的默認隔離級别是REPEATABLE-READ。

阿裡面試題mysql優化(我以為我對Mysql事務很熟)1

「我:」 先來演示一下讀未提交,先把默認的隔離級别修改為READ UNCOMMITTED。

阿裡面試題mysql優化(我以為我對Mysql事務很熟)2

「我:」 他設置隔離級别的語句中set global transaction isolation level read uncommitted,這裡的global也可以換成session,global表示全局的,而session表示當前會話,也就是當前窗口有效。

「我:」 當設置完隔離級别後對于之前打開的會話,是無效的,要重新打開一個窗口設置隔離級别才生效。

阿裡面試題mysql優化(我以為我對Mysql事務很熟)3

「我:」 然後是開啟事務,Mysql中開啟事務有兩種方式begin/start transaction,最後提交事務執行commit,或者回滾事務rollback。

「我:」 在執行begin/start transaction命令,它們并不是一個事務的起點,在執行完它們後的第一個sql語句,才表示事務真正的啟動 。

「我:」 這裡直接打開兩個新的窗口,同時開啟事務,再第一個窗口先update一個id=1的數據行name改為'非科班的科班',執行成功。

阿裡面試題mysql優化(我以為我對Mysql事務很熟)4

「我:」 然後再第二個窗口執行兩次的查詢,分别是窗口一update之前的查詢和update之後的查詢。

阿裡面試題mysql優化(我以為我對Mysql事務很熟)5

「我:」 第一個session産生的未提交的事務的狀态就會直接影響到第二sesison,也就是髒讀。

「我:」 對于讀提交也是一樣的,開啟事務後,第一個事務先執行查詢數據,然後第二個session執行update操作,但是還沒有commit,這是第一個session再次select,數據并沒有改變,在第二個session執行commit之後,第一個session再次select就是改變後的數據了。

阿裡面試題mysql優化(我以為我對Mysql事務很熟)6

「我:」 這樣第一個事務的查詢結果就會受到第二事務的影響,這個也就是産生不可重複讀的問題。

「面試官:」 小夥子你能畫一下他執行的過程圖嗎?你講的我有點亂,我還沒有徹底明白。

我心裡一萬隻什麼馬在飛過,欲哭無淚,這面試官真難伺候,說時遲那時快,從左屁股兜抽出筆,從右屁股兜拿出紙,開始畫。

阿裡面試題mysql優化(我以為我對Mysql事務很熟)7

「我:」 這個是讀提交的時間軸圖,讀未提交的時間軸圖,原理也一樣的,第二個select的時候數據就已經改變了。

這是面試官拿過我的圖看了一點,微微的點了點頭,嘴角露出思思的笑意,我想你這糟老頭子應該不會再刁難我了吧。

「面試官:」 嗯,你接着演示你的可重複讀吧。

「我:」 嗯,好的,然後就是可重複讀,和之前一樣的操作。

阿裡面試題mysql優化(我以為我對Mysql事務很熟)8

「我:」 将兩個session開啟為REPEATABLE READ,同時開啟事務,在第一個事務中先select,然後在第二個事務裡面update數據行,可以發現即使第二個事務已經commit,第一個事務再次select數據也還是沒有改變,這就解決了不可重複讀的問題。

「我:」 這裡有個不同的地方就是在Mysql中,默認的不可重複讀個隔離級别也解決了幻讀的問題。

「我:」 從上面的演示中可以看出第一個事務中先select一個id=3的數據行,這條數據行是不存在的,返回Empty set,然後第二個事務中insert一條id=3的數據行并且commit,第一個事務中再次select的,數據也好是沒有id=3的數據行。

「我:」 最後的串行化,樣式步驟也是一樣的,結果也和Mysql中默認的個可重複讀隔離級别的結果一樣,串行化的執行流程相當于把事務的執行過程變為順序執行,我這邊就不再做演示了。

「我:」 這四大等級從上到下,隔離的效果是逐漸增強,但是性能卻是越來越差。

Mysql的鎖機制

「面試官:」 哦?性能越來越差?為什麼會性能越來越差?你能說一說原因嗎?

哎呀,我這嘴,少說一句會死啊,這下好了,這個得說底層實現原理了,從原來得假裝若有所思,變成了真正得若有所思。

「我:」 這個得從Mysq的鎖說起,在Mysql中的鎖可以分為分「享鎖/讀鎖(Shared Locks)」「排他鎖/寫鎖(Exclusive Locks)」「間隙鎖」「行鎖(Record Locks)」「表鎖」

「我:」 在四個隔離級别中加鎖肯定是要消耗性能的,而讀未提交是沒有加任何鎖的,所以對于它來說也就是沒有隔離的效果,所以它的性能也是最好的。

「我:」 對于串行化加的是一把大鎖,讀的時候加共享鎖,不能寫,寫的時候,加的是排它鎖,阻塞其它事務的寫入和讀取,若是其它的事務長時間不能寫入就會直接報超時,所以它的性能也是最差的,對于它來就沒有什麼并發性可言。

「我:」 對于讀提交和可重複讀,他們倆的實現是兼顧解決數據問題,然後又要有一定的并發性,所以在實現上鎖機制會比串行化優化很多,提高并發性,所以性能也會比較好。

「我:」 他們倆的底層實現采用的是MVCC(多版本并發控制)方式進行實現。

「面試官:」 你能先說一下先這幾個鎖的概念嗎?我不是很懂,說說你的理解。

「我:」 哦,好的,共享鎖是針對同一份數據,多個讀操作可以同時進行,簡單來說即讀加鎖,不能寫并且可并行讀;排他鎖針對寫操作,假如當前寫操作沒有完成,那麼它會阻斷其它的寫鎖和讀鎖,即寫加鎖,其它讀寫都阻塞 。

「我:」 而行鎖和表鎖,是從鎖的粒度上進行劃分的,行鎖鎖定當前數據行,鎖的粒度小,加鎖慢,發生鎖沖突的概率小,并發度高,行鎖也是MyISAM和InnoDB的區别之一,InnoDB支持行鎖并且支持事務 。

「我:」 而表鎖則鎖的粒度大,加鎖快,開銷小,但是鎖沖突的概率大,并發度低。

「我:」 間隙鎖則分為兩種:Gap Locks和Next-Key Locks。Gap Locks會鎖住兩個索引之間的區間,比如select * from User where id>3 and id<5 for update,就會在區間(3,5)之間加上Gap Locks。

「我:」 Next-Key Locks是Gap Locks Record Locks形成閉區間鎖select * from User where id>=3 and id=<5 for update,就會在區間[3,5]之間加上Next-Key Locks。

「面試官:」 那Mysql中什麼時候會加鎖呢?

「我:」 在數據庫的增、删、改、查中,隻有增、删、改才會加上排它鎖,而隻是查詢并不會加鎖,隻能通過在select語句後顯式加lock in share mode或者for update來加共享鎖或者排它鎖。

事務底層實現原理

「面試官:」 你在上面提到MVCC(多版本并發控制),你能說一說原理嗎?

「我:」 在實現MVCC時用到了一緻性視圖,用于支持讀提交和可重複讀的實現。

「我:」 在實現可重複讀的隔離級别,隻需要在事務開始的時候創建一緻性視圖,也叫做快照,之後的查詢裡都共用這個一緻性視圖,後續的事務對數據的更改是對當前事務是不可見的,這樣就實現了可重複讀。

「我:」 而讀提交,每一個語句執行前都會重新計算出一個新的視圖,這個也是可重複讀和讀提交在MVCC實現層面上的區别。

「面試官:」 那你知道快照(視圖)在MVCC底層是怎麼工作的嗎?

「我:」 在InnoDB 中每一個事務都有一個自己的事務id,并且是唯一的,遞增的 。

「我:」 對于Mysql中的每一個數據行都有可能存在多個版本,在每次事務更新數據的時候,都會生成一個新的數據版本,并且把自己的數據id賦值給當前版本的row trx_id。

「面試官:」 小夥子你可以畫個圖我看看嗎?我不是很明白。

我有什麼辦法呢?完全沒辦法,隻能又從屁股兜裡拿出筆和紙,迅速的畫了起來,相當這次面試要是不過血虧啊,浪費了我兩張紙和筆水,多貴啊,隻能豁出去了。

阿裡面試題mysql優化(我以為我對Mysql事務很熟)9

「我:」 如圖中所示,假如三個事務更新了同一行數據,那麼就會有對應的三個數據版本。

「我:」 實際上版本1、版本2并非實際物理存在的,而圖中的U1和U2實際就是undo log,這v1和v2版本是根據當前v3和undo log計算出來的。

「面試官:」 那對于一個快照來說,你知道它要遵循什麼規則嗎?

「我:」 嗯,對于一個事務視圖來說除了對自己更新的總是可見,另外還有三種情況:版本未提交的,都是不可見的;版本已經提交,但是是在創建視圖之後提交的也是不可見的;版本已經提交,若是在創建視圖之前提交的是可見的。

「面試官:」 假如兩個事務執行寫操作,又怎麼保證并發呢?

「我:」 假如事務1和事務2都要執行update操作,事務1先update數據行的時候,先回獲取行鎖,鎖定數據,當事務2要進行update操作的時候,也會去獲取該數據行的行鎖,但是已經被事務1占有,事務2隻能wait。

「我:」 若是事務1長時間沒有釋放鎖,事務2就會出現超時異常 。

「面試官:」 這個是在update的where後的條件是在有索引的情況下吧?

「我:」 嗯,是的 。

「面試官:」 那沒有索引的條件下呢?沒辦法快速定位到數據行呢?

「我:」 若是沒有索引的條件下,就獲取所有行,都加上行鎖,然後Mysql會再次過濾符合條件的的行并釋放鎖,隻有符合條件的行才會繼續持有鎖。

「我:」 這樣的性能消耗也會比較大。

「面試官:」 嗯嗯

此時面試官看看手表一個多鐘已經過去了,也已經到了飯點時刻,我想他應該是肚子餓了,不會繼續追問吧,兩人持續僵了三十秒,他終于開口了。

「面試官:」 小夥子,現在時間也已經到了飯點了,今天的面試就到此結束吧,你回去等通知吧。

「我:」 。。。。。。。。。。

來源:掘金 鍊接:https://juejin.im/post/5ede6436518825430c3acaf4

,
Comments
Welcome to tft每日頭條 comments! Please keep conversations courteous and on-topic. To fosterproductive and respectful conversations, you may see comments from our Community Managers.
Sign up to post
Sort by
Show More Comments
推荐阅读
怎麼才能不讓别人看到excel公式
怎麼才能不讓别人看到excel公式
Hello,大家好,今天跟大家分享下如何設置公式保護,當我們使用公式将表格彙總統計完畢後,最怕的就是一不小心更改或者删除了某個公式,這樣的話就會造成數據的錯誤。因為公式是即刻刷新的,就是算被更改了,也不能快速的查找出具體哪個數據被更改了,所...
2024-04-29
優秀員工的獎金怎麼拿
優秀員工的獎金怎麼拿
分享工具、案例和好書,助你職場不迷茫年終獎金怎麼發才對員工最起作用?這個問題讓不少企業的領導和HR經理發愁。在很多人看來,企業在每一年開始的時候都應設定自己的發展目标,分解到部門和個人,年底按照目标進行考評,根據目标的完成情況來分配獎金,這...
2024-04-29
懷孕上班可以帶飯吃嗎
懷孕上班可以帶飯吃嗎
導讀:對于很多職場女性來說懷孕之後并不會立馬辭職在家養胎,而是會繼續上班工作,而懷孕的女性日常的飲食就不能像平時那樣随便應付了事。平時吃外賣、吃餐館的吃飯方式就不适用了,因此,為了孕期的營養健康吸收,很多孕媽們都會選擇帶飯上班。而在孕期的飲...
2024-04-29
汽油發動機工作原理簡化圖
汽油發動機工作原理簡化圖
發動機是一種動力源。發動機是将某一種形式的能量轉換為機械能的機器。燃油發動機的作用是将燃料的化學能通過燃燒轉化為熱能,再把熱能通過膨脹轉化為機械能,對外輸出動力。小型農業機械一般采用的發動機為單缸二沖程發動機和四沖程發動機。如圖所示:第一節...
2024-04-29
excel如何快速批量生成多個excel
excel如何快速批量生成多個excel
大家好,如果公司領導要求按人員姓名制作文件夾,以一人一檔的形式呈現人員檔案,辦公人員一個一個制作費時費力,而且效力低下,今天為大家介紹快捷制作批量文件夾的方法下面我們用圖片來進行演示操作打開表格,選擇B2:B16,按CtrlC複制姓名選擇旁...
2024-04-29
Copyright 2023-2024 - www.tftnews.com All Rights Reserved