關於MySQL的索引,曾經進行過一次總結,文章連結在這裡 Mysql索引原理及其優化.1. 什麼是索引?索引是一種資料結構,可以幫助我們快速地進行資料的查詢.2. 索引是個什麼樣的資
2021-08-17 11:06:35
我的工作是python伺服器開發工程師,最近準備看看其他工作機會,也面試了一些公司。MySQL基本是一定會被問到的知識點,所以最近又開始惡補相關的知識點。面試過程中越來越覺得面試官真的很重要,他是面試者瞭解公司最直接的一個途徑,也是公司技術的把關者。所以我也在思考一個問題,假如我是面試官我會怎麼考察面試者?
首先面試最本質的目的是招收合理的人來工作,所以應該要避免的問題是「面試內容是造火箭,結果工作內容卻是搬磚」。所以要問的問題最好是貼近生產環境的。其次面試通常會涉及很多概念,工作比較久的同學通常容易忘記這些東西。所以我覺得沒有必要考察概念,而是考察這些概念的本質,這些本質的東西是不容易忘記的。
這裡說明一下,通常業務中用得最多的是Innodb,所以以下問題都是基於Innodb的。
問題一:考察資料隔離和事務
第一階段:
MySQL的隔離級別有如下四種,預設的級別是什麼?
READ-UNCOMMITTED
READ-COMMITTED
REPEATABLE-READ
SERIALIZABLE
REPEATABLE-READ。這個應該是常識,大家都知道的。這裡需要讓面試者解釋一下隔離級別的意義,因為後面的問題是基於這個概念的。如果面試者忘了概念建議提示一下,繼續下一個問題。
READ-UNCOMMITTED:表示可以讀取到未提交的資料
READ-COMMITTED:可以讀取到已經提交的資料
REPEATABLE-READ:可重複讀,每次讀取的結果都是一樣的。
SERIALIZABLE 完全序列化的讀,每次讀都需要獲得共享鎖,讀寫相互都會阻塞
這裡很多面試官會問一個REPEATABLE-READ怎麼解決幻讀的問題。當時有點蒙,「幻讀」是什麼東西。其實本質上很簡單,幻讀其實就是MySQL怎麼確保「可重複讀」這個功能的。具體的名詞叫資料多版本併發控制(MVCC)。不過這個應該是比較底層的知識,屬於Nice to have了。
第二階段
有一張表user_count,這個表記錄的是不同國家使用者的個數。現在如下程式碼會在以上四個級別的隔離中分別執行一次,請問結果分別是什麼?注意,以下程式碼是在5000個執行緒中執行的,所以是併發執行的。
資料樣例:
+--------+--------+
| region | number |
| us | 0 |
| cn | 0 |
程式碼:
@dec_multi_thread_run(5000)
def do():
try:
# get old num from table
num = "select number from user_count where region = 'cn'"
# update to new value
"update user_count set number = %s where region = 'cn' " % (num +1)
except:
rollback()
else:
commit()
首先問這個問題的話,面試者肯定知道答案不是5000,而是小於5000。大部分人會根據隔離級別越來越高判斷結果的值會越來越小,而真實結果如下。
read uncommitted,3271
read committed,2638
repeatable read,2551
serializable,3052
對於前三個結果遞減比較容易解釋,因為隨著事務隔離級別變高越不可能讀到髒資料。但對於serializable,直觀的結果應該是返回5000,因為序列化級別是不會讀到髒資料的。但實際上這裡考察的是一個會出現死鎖的問題。serializable級別會對讀取加上一個共享鎖,也就是說在多執行緒下會出現很多事務同時獲取到了共享鎖。然後當要執行update操作去獲取排它鎖時就會出現死鎖了。也就是說某些更新會失敗造成結果小於5000。這裡考察到了serializable具體的底層執行方式。
如果問的深入一點,可以問下MySQL檢查死鎖的方式以及怎麼自動解除死鎖的。當然,這個也是Nice to have的。在看參考資料1的時候,有提到對高併發業務的優化。具體的方式就是關閉死鎖檢測,然後用一個較短的timout時間替代。不過我沒有親自驗證,有興趣的同學可以自行驗證一下。
第三階段
怎麼優化上面的程式碼,使結果為5000
這個比較簡單,主要是考察一下面試者知不知道鎖的概念。 select 語句後面加一個for update就解決問題了。
如果把語句改成update user_count set number = number + 1 where region = 'cn' 在四個事務級別下結果分別是多少?
結果都是5000,因為MySQL會預設在insert,update,delete時增加一個排他鎖,Nice to have。
問題二:索引
有一個user表,id是自增主鍵,記錄的是使用者的資訊。資料量是1000萬行,請建立索引並優化用到的查詢。
+--------+--------------+----------+----------+--------------+
| id | country user_ name sex create_time |
| 1 | cn | alice | female | 1559476160 |
| 2 | us | bob | male | 1559476170 |
用到的查詢語句
-- 查詢叫Alice的人
select * from user where user_name = "alice";
-- 查詢國家是us叫Alice的人
select * from user where country = "us" and user_name = "alice";
-- 查詢所有叫Alice的女性
select * from user where sex = "female" and user_name = "alice";
-- 展示最新註冊的10個使用者
select * from user order by create_time desc limit 10;
最優解是隻用一個聯合索引(user_name, country)並調整一下語句2和語句3的查詢順序,username放在前面。
針對第一個語句,只查詢user_name也能利用到聯合索引。針對語句2完美利用了聯合索引。針對語句三不用對sex建立索引,因為區分度太低沒有意義。針對語句4自增id預設就是按照時間遞增的,所以沒有必要再增加索引了。
第二階段:
通常在設計資料庫的時候都會用到自增id,具體的原因是什麼?
答案是增加資料插入的速度。知道這裡就夠了。下一個階段是Nice to Have
第三階段:
MySQL索引的資料結構是什麼?為什麼要用這個結構?
因為MySQL儲存的資料結構用的是B+樹。B+樹和B樹(多路平衡查詢樹)的主要區別是B+樹所有的資料都是儲存在葉子節點的。通常B+樹的層級都是很少的,單個非根節點會儲存很多的資料,這樣可以減少讀取索引的次數。因為機械磁碟擅長的是大塊地順序讀寫,一次性讀到越多的資料越有利於快速查詢,而且B+樹有個好處,所有的葉子節點都是指針相連的,可以快速地進行全表便利。所以是個特別適合資料庫的資料結構。
以上是我能想到的兩大問題(其實我就準備了這些 ),日常開發中我覺得知道MySQL的這兩個問題應該就夠了,如果有其他好的問題還請各位不吝賜教
相關文章
關於MySQL的索引,曾經進行過一次總結,文章連結在這裡 Mysql索引原理及其優化.1. 什麼是索引?索引是一種資料結構,可以幫助我們快速地進行資料的查詢.2. 索引是個什麼樣的資
2021-08-17 11:06:35
【8月17日訊】相信大家都知道,在最近幾年時間裡,有關於國產晶片、國產作業系統發展,再次受到了國內消費者以及各大國產廠商的高度重視,因為在美國的「實體清單」制裁之下,目前國
2021-08-17 11:06:20
耕升宣佈推出了新的GeForce RTX 30 Phantom系列產品:GeForce RTX 3080 Ti Phantom。原有的GeForce RTX 30 Phantom系列顯示卡推出升級的GeForce RTX 30 Phantom+系列,將使用新
2021-08-17 11:06:11
炎熱的八月已經過去了一半,各位小夥伴的暑期生活過的怎麼樣呢?是頂著火辣的太陽出門逛街,還是在家吹著空調過上清爽舒適的宅家生活,相信不少人都是選擇後者,當然,整天躺在家裡只是
2021-08-17 11:05:39
8月10日晚,小米釋出了旗下首款搭載屏下攝像頭的全面屏手機-小米MIX4,而且起售價僅為4999元,比小米11 Ultra還便宜1000元。8月16日上午,小米MIX4正式上市。根據小米官方的資料,小
2021-08-17 11:05:28
別留遺憾,這應該是消費者對手機廠商想說的一句話,因為現在的手機產品幾乎都存在著十分明顯的優缺點,甚至讓使用者失去了選擇興趣。比如想使用屏下鏡頭設計,那麼就不能體驗到十分
2021-08-17 11:05:13