想进阿里必须啃透的 13 道 MySQL 面试题
? 篇幅所限本文只寫了 12 道經典 MySQL 面試題,像其他的 Redis,SSM 框架,算法,計網等技術棧的面試題后面會持續更新,個人整理的 1000 余道面試八股文會放在文末給大家白嫖,最近有面試需要刷題的同學可以直接翻到文末領取。
本文目錄:
1. 能說下 myisam 和 innodb 的區別嗎?
2. 說下 mysql 的索引有哪些吧,聚簇和非聚簇索引又是什么?
3. 那你知道什么是覆蓋索引和回表嗎?
4. 鎖的類型有哪些呢
5. 你能說下事務的基本特性和隔離級別嗎?
6. 那你說說什么是幻讀,什么是 MVCC?
8. 那你知道什么是間隙鎖嗎?
9. 那分表后的 ID 怎么保證唯一性的呢?
10. 你們數據量級多大?分庫分表怎么做的?
11. 分表后非 sharding_key 的查詢怎么處理呢?
12. 說說 mysql 主從同步怎么做的吧?
13. 那主從的延遲怎么解決呢?
正文:
1. 能說下 myisam 和 innodb 的區別嗎?
myisam 引擎是 5.1 版本之前的默認引擎,支持全文檢索、壓縮、空間函數等,但是不支持事務和行級鎖,所以一般用于有大量查詢少量插入的場景來使用,而且 myisam 不支持外鍵,并且索引和數據是分開存儲的。
innodb 是基于聚簇索引建立的,和 myisam 相反它支持事務、外鍵,并且通過 MVCC 來支持高并發,索引和數據存儲在一起。
2. 說下 mysql 的索引有哪些吧,聚簇和非聚簇索引又是什么?
索引按照數據結構來說主要包含 B+樹和 Hash 索引。
假設我們有張表,結構如下:
create table user( id int(11) not null, age int(11) not null, primary key(id), key(age));復制代碼
B+樹是左小右大的順序存儲結構,節點只包含 id 索引列,而葉子節點包含索引列和數據,這種數據和索引在一起存儲的索引方式叫做聚簇索引,一張表只能有一個聚簇索引。假設沒有定義主鍵,InnoDB 會選擇一個唯一的非空索引代替,如果沒有的話則會隱式定義一個主鍵作為聚簇索引。
這是主鍵聚簇索引存儲的結構,那么非聚簇索引的結構是什么樣子呢?非聚簇索引(二級索引)保存的是主鍵 id 值,這一點和 myisam 保存的是數據地址是不同的。
?
最終,我們一張圖看看 InnoDB 和 Myisam 聚簇和非聚簇索引的區別
?
3. 那你知道什么是覆蓋索引和回表嗎?
覆蓋索引指的是在一次查詢中,如果一個索引包含或者說覆蓋所有需要查詢的字段的值,我們就稱之為覆蓋索引,而不再需要回表查詢。
而要確定一個查詢是否是覆蓋索引,我們只需要 explain sql 語句看 Extra 的結果是否是“Using index”即可。
以上面的 user 表來舉例,我們再增加一個 name 字段,然后做一些查詢試試。
explain select * from user where age=1; //查詢的name無法從索引數據獲取explain select id,age from user where age=1; //可以直接從索引獲取復制代碼
4. 鎖的類型有哪些呢
mysql 鎖分為共享鎖和排他鎖,也叫做讀鎖和寫鎖。
讀鎖是共享的,可以通過 lock in share mode 實現,這時候只能讀不能寫。
寫鎖是排他的,它會阻塞其他的寫鎖和讀鎖。從顆粒度來區分,可以分為表鎖和行鎖兩種。
表鎖會鎖定整張表并且阻塞其他用戶對該表的所有讀寫操作,比如 alter 修改表結構的時候會鎖表。
行鎖又可以分為樂觀鎖和悲觀鎖,悲觀鎖可以通過 for update 實現,樂觀鎖則通過版本號實現。
5. 你能說下事務的基本特性和隔離級別嗎?
事務基本特性 ACID 分別是:
原子性指的是一個事務中的操作要么全部成功,要么全部失敗。
一致性指的是數據庫總是從一個一致性的狀態轉換到另外一個一致性的狀態。比如 A 轉賬給 B100 塊錢,假設中間 sql 執行過程中系統崩潰 A 也不會損失 100 塊,因為事務沒有提交,修改也就不會保存到數據庫。
隔離性指的是一個事務的修改在最終提交前,對其他事務是不可見的。
持久性指的是一旦事務提交,所做的修改就會永久保存到數據庫中。
而隔離性有 4 個隔離級別,分別是:
read uncommit 讀未提交,可能會讀到其他事務未提交的數據,也叫做臟讀。
用戶本來應該讀取到 id=1 的用戶 age 應該是 10,結果讀取到了其他事務還沒有提交的事務,結果讀取結果 age=20,這就是臟讀。
read commit 讀已提交,兩次讀取結果不一致,叫做不可重復讀。
不可重復讀解決了臟讀的問題,他只會讀取已經提交的事務。
用戶開啟事務讀取 id=1 用戶,查詢到 age=10,再次讀取發現結果=20,在同一個事務里同一個查詢讀取到不同的結果叫做不可重復讀。
repeatable read 可重復復讀,這是 mysql 的默認級別,就是每次讀取結果都一樣,但是有可能產生幻讀。
serializable 串行,一般是不會使用的,他會給每一行讀取的數據加鎖,會導致大量超時和鎖競爭的問題。
6. 那你說說什么是幻讀,什么是 MVCC?
要說幻讀,首先要了解 MVCC,MVCC 叫做多版本并發控制,實際上就是保存了數據在某個時間節點的快照。
我們每行數據實際上隱藏了兩列,創建時間版本號,過期(刪除)時間版本號,每開始一個新的事務,版本號都會自動遞增。
還是拿上面的 user 表舉例子,假設我們插入兩條數據,他們實際上應該長這樣。
?
這時候假設小明去執行查詢,此時 current_version=3
select * from user where id<=3;復制代碼
同時,小紅在這時候開啟事務去修改 id=1 的記錄,current_version=4
update user set name='張三三' where id=1;復制代碼
執行成功后的結果是這樣的
如果這時候還有小黑在刪除 id=2 的數據,current_version=5,執行后結果是這樣的。
由于 MVCC 的原理是查找創建版本小于或等于當前事務版本,刪除版本為空或者大于當前事務版本,小明的真實的查詢應該是這樣
select * from user where id<=3 and create_version<=3 and (delete_version>3 or delete_version is null);復制代碼
所以小明最后查詢到的 id=1 的名字還是'張三',并且 id=2 的記錄也能查詢到。這樣做是為了保證事務讀取的數據是在事務開始前就已經存在的,要么是事務自己插入或者修改的。
明白 MVCC 原理,我們來說什么是幻讀就簡單多了。舉一個常見的場景,用戶注冊時,我們先查詢用戶名是否存在,不存在就插入,假定用戶名是唯一索引。
小明開啟事務 current_version=6 查詢名字為'王五'的記錄,發現不存在。
小紅開啟事務 current_version=7 插入一條數據,結果是這樣:
小明執行插入名字'王五'的記錄,發現唯一索引沖突,無法插入,這就是幻讀。
7. 那 ACID 靠什么保證的呢?
A 原子性由 undo log 日志保證,它記錄了需要回滾的日志信息,事務回滾時撤銷已經執行成功的 sql
C 一致性一般由代碼層面來保證
I 隔離性由 MVCC 來保證
D 持久性由內存+redo log 來保證,mysql 修改數據同時在內存和 redo log 記錄這次操作,事務提交的時候通過 redo log 刷盤,宕機的時候可以從 redo log 恢復
8. 那你知道什么是間隙鎖嗎?
....博主太懶了字數太多了,不想寫了....文章已經做成PDF,有需要的朋友可以私信我免費獲取!
?
?
總結
以上是生活随笔為你收集整理的想进阿里必须啃透的 13 道 MySQL 面试题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redis核心技术与实战-学习笔记(十五
- 下一篇: yum 安装mysql 5.7