MySQL面試複習題
阿新 • • 發佈:2021-01-14
MySQL 索引的原理和資料結構能介紹一下嗎?
- MySQL使用的資料結構為B+樹
B+ 樹和 B- 樹有什麼區別?
- B-樹的資料是存放在索引結點上,而B+樹的資料是存放在索引結點只作為索引使用,資料存放在葉子結點上(MyIsam和Innodb不一樣)
- B+樹葉子結點的資料都存放在連結串列中,且連結串列資料都是有序儲存的
為什麼MySQL資料庫索引使用B+樹
- 跟其他樹相比,B+樹索引結點上並沒有存放具體資料,因此磁碟讀寫代價更低。
- 根據上面說到的,B+樹葉子結點存放在連結串列的特性,非常適合做範圍查詢。
使用 MySQL 索引都有哪些原則?
- 索引不宜過多,過多的索引會導致操作執行效率低下
- 只對查詢頻繁的欄位做索引
- 對排序、分組、聯合查詢頻率高的欄位做索引
MySQL 聚簇索引和二級索引的區別是什麼?他們分別是如何儲存的?
- 資料儲存和索引都在一起,炸到索引就能找到資料。
- 資料儲存和索引是分開的,在innodb中,二級索引儲存的並非資料實體地址,而是主鍵值,因此通過二級索引查詢會導致查詢兩次。
MySQL InnoDB 如何防止記憶體緩衝區被汙染?
緩衝池機制主要目的是避免每次訪問磁碟,快速資料訪問。
InnoDB是使用LRU演算法來管理緩衝頁。
但傳統的LRU連結串列是無法滿足Mysql的要求的,主要有兩個問題:
-
預讀失效
Mysql會預先把可能會被訪問的資料提前放入緩衝池,但如果大量沒擊中,那就很浪費效能了。
這時候Mysql就對LRU進行了優化,拆分為兩部分
新生代(5/8):存放真正預讀成功的資料,並延長他的存活時間。
老生代(3/8):存放預讀的資料,但存活時間會盡可能短。
這樣就能解決預讀失敗了,但解決不了緩衝池汙染。
-
緩衝池汙染
在掃描大量資料時,頁會把資料載入到緩衝池(老年代的頭部),然後在1s不到又訪問到了他,這時候他就會成為熱資料,而假如是全表掃描的話,那就會把所有的真正的熱資料被大量換出。
因此Mysql加入了“老生代停留時間視窗(innodb_old_blocks_time)”的機制,只有在“被訪問”並且大於“老生代停留時間視窗”,才會被放入新生代頭部。預設是1000
參考文章:
MySQL InnoDB 事務隔離級別如何實現?
隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|
未提交讀(Read uncommitted) | 可能 | 可能 | 可能 |
已提交讀(Read committed) | 不可能 | 可能 | 可能 |
可重複讀(Repeatable read) | 不可能 | 不可能 | 可能 |
可序列化(Serializable) | 不可能 | 不可能 | 不可能 |
- 未提交讀(Read Uncommitted):允許髒讀,也就是可能讀取到其他會話中未提交事務修改的資料
- 已提交讀(Read Committed):只能讀取到已經提交的資料。Oracle等多數資料庫預設都是該級別 (不重複讀)
- 可重複讀(Repeated Read):可重複讀。在同一個事務內的查詢都是事務開始時刻一致的,InnoDB預設級別。在SQL標準中,該隔離級別消除了不可重複讀,但是還存在幻象讀
- 可序列化(Serializable):完全序列化的讀,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞
InnoDB預設是行級鎖,內部會生成三個隱藏欄位:db_trx_id(
事務id)、db_roll_pt
(回滾指標)、delete_flag
(刪除標記)
版本鏈使用場景(readView)
- 當前操作的事務id為102,假設版本鏈資料[1,2,100,101],活躍列表為[100,101],活躍列表就是未提交的活躍事務,因此事務2是已提交,所以事務5會拷貝一份事務2並插入版本鏈最後一個元素
- 當隔離界別為可重複讀,需要操作事務查詢或修改時,那麼就單獨讀取事務102的資料,這樣就能實現隔離其他未提交的事務。
- 當隔離界別為讀已提交,流程跟可重複讀差不多,但在每次讀取資料前都會生成一個readView,保證不會查詢到當前事務未提交的資料。
DML操作
- INSERT:建立一條資料,
db_trx_id
的值為當前事務 id,db_roll_pt
為 null 。 - UPDATE:複製一行資料,將當前複製後這一行的
db_trx_id
置為當前事務的 id,db_roll_pt
是一個指標,指向複製前的那一條的。 - DELETE:複製一行資料,將當前複製後這一行的
db_trx_id
置為當前事務的 id,db_roll_pt
是一個指標,指向複製前的那一條的。並把delete_flag
置為 true 。
B+樹是如何分裂的
待更新