號外號外!《死磕 Java 并發編程》系列連載中,大家可以關注一波:
「死磕 Java 并發編程05」阿里面試失敗后,一氣之下我圖解了Java中18把鎖
「死磕 Java 并發編程04」說說Java Atomic 原子類的實作原理
「死磕 Java 并發編程03」阿里二面,面試官:說說 Java CAS 原理?
「死磕 Java 并發編程02」面試官:說說什么是 Java 記憶體模型(JMM)?
「死磕 Java 并發編程01」10張圖告訴你Java并發多執行緒那些破事
先看下目錄:
1 說說MySQL 的基礎架構圖
2 一條SQL查詢陳述句在MySQL中如何執行的?
3 日常作業中你是怎么優化SQL的?
4 怎么看執行計劃(explain),如何理解其中各個欄位的含義?
5 關心過業務系統里面的sql耗時嗎?統計過慢查詢嗎?對慢查詢都怎么優化過?
6 聚集索引與非聚集索引的區別
7 為什么要用 B+ 樹,為什么不用普通二叉樹?
8 Hash 索引和 B+ 樹索引區別是什么?你在設計索引是怎么抉擇的?
9 什么是最左前綴原則?什么是最左匹配原則?
10 索引不適合哪些場景?
11 索引有哪些優缺點?
12 MySQL 遇到過死鎖問題嗎,你是如何解決的?
13 說說資料庫的樂觀鎖和悲觀鎖是什么以及它們的區別?
14 MVCC 熟悉嗎,知道它的底層原理?
15 MySQL事務得四大特性以及實作原理
16 事務的隔離級別有哪些?MySQL的默認隔離級別是什么?
17 什么是幻讀,臟讀,不可重復讀呢?
18 MySQL資料庫cpu飆升的話,要怎么處理呢?
19 MYSQL的主從延遲,你怎么解決?
20 如果讓你做分庫與分表的設計,簡單說說你會怎么做?
在奪命 20 問要開始了之前推薦一份阿里大佬總結的面試資料,覆寫了資料結構、計算機網路、作業系統、 Java 核心知識、面經等,對編程學習幫助很大:
看完阿里師兄總結的Java知識筆記,秒殺一線大廠面試(283 頁,含下載方式)
資料庫架構
說說MySQL 的基礎架構圖
給面試官講一下 MySQL 的邏輯架構,有白板可以把下面的圖畫一下,
Mysql邏輯架構圖主要分三層: (1)第一層負責連接處理,授權認證,安全等等 (2)第二層負責編譯并優化SQL (3)第三層是存盤引擎,
一條SQL查詢陳述句在MySQL中如何執行的?
-
先檢查該陳述句
是否有權限,如果沒有權限,直接回傳錯誤資訊,如果有權限會先查詢快取(MySQL8.0 版本以前), -
如果沒有快取,分析器進行
詞法分析,提取 sql 陳述句中 select 等關鍵元素,然后判斷 sql 陳述句是否有語法錯誤,比如關鍵詞是否正確等等, -
最后優化器確定執行方案進行權限校驗,如果沒有權限就直接回傳錯誤資訊,如果有權限就會
呼叫資料庫引擎介面,回傳執行結果,
SQL 優化
日常作業中你是怎么優化SQL的?
可以從這幾個維度回答這個問題:
1,優化表結構
(1)盡量使用數字型欄位
若只含數值資訊的欄位盡量不要設計為字符型,這會降低查詢和連接的性能,并會增加存盤開銷, 這是因為引擎在處理查詢和連接時會逐個比較字串中每一個字符,而對于數字型而言只需要比較一次就夠了,
(2)盡可能的使用 varchar 代替 char
變長欄位存盤空間小,可以節省存盤空間,
(3)當索引列大量重復資料時,可以把索引洗掉掉
比如有一列是性別,幾乎只有男、女、未知,這樣的索引是無效的,
2,優化查詢
-
應盡量避免在 where 子句中使用!=或<>運算子
-
應盡量避免在 where 子句中使用 or 來連接條件
-
任何查詢也不要出現select *
-
避免在 where 子句中對欄位進行 null 值判斷
3,索引優化
-
對作為查詢條件和 order by的欄位建立索引
-
避免建立過多的索引,多使用組合索引
怎么看執行計劃(explain),如何理解其中各個欄位的含義?
在 select 陳述句之前增加 explain 關鍵字,會回傳執行計劃的資訊,

(1)id 列:是 select 陳述句的序號,MySQL將 select 查詢分為簡單查詢和復雜查詢,
(2)select_type列:表示對應行是是簡單還是復雜的查詢,
(3)table 列:表示 explain 的一行正在訪問哪個表,
(4)type 列:最重要的列之一,表示關聯型別或訪問型別,即 MySQL 決定如何查找表中的行, 從最優到最差分別為:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
(5)possible_keys 列:顯示查詢可能使用哪些索引來查找,
(6)key 列:這一列顯示 mysql 實際采用哪個索引來優化對該表的訪問,
(7)key_len 列:顯示了mysql在索引里使用的位元組數,通過這個值可以算出具體使用了索引中的哪些列,
(8)ref 列:這一列顯示了在key列記錄的索引中,表查找值所用到的列或常量,常見的有:const(常量),func,NULL,欄位名,
(9)rows 列:這一列是 mysql 估計要讀取并檢測的行數,注意這個不是結果集里的行數,
(10)Extra 列:顯示額外資訊,比如有 Using index、Using where、Using temporary等,
關心過業務系統里面的sql耗時嗎?統計過慢查詢嗎?對慢查詢都怎么優化過?
我們平時寫Sql時,都要養成用explain分析的習慣,慢查詢的統計,運維會定期統計給我們
優化慢查詢思路:
-
分析陳述句,是否加載了不必要的欄位/資料
-
分析 SQL 執行句話,是否命中索引等
-
如果 SQL 很復雜,優化 SQL 結構
-
如果表資料量太大,考慮分表
索引
聚集索引與非聚集索引的區別
可以按以下四個維度回答:
(1)一個表中只能擁有一個聚集索引,而非聚集索引一個表可以存在多個,
(2)聚集索引,索引中鍵值的邏輯順序決定了表中相應行的物理順序;非聚集索引,索引中索引的邏輯順序與磁盤上行的物理存盤順序不同,
(3)索引是通過二叉樹的資料結構來描述的,我們可以這么理解聚簇索引:索引的葉節點就是資料節點,而非聚簇索引的葉節點仍然是索引節點,只不過有一個指標指向對應的資料塊,
(4)聚集索引:物理存盤按照索引排序;非聚集索引:物理存盤不按照索引排序;
為什么要用 B+ 樹,為什么不用普通二叉樹?
可以從幾個維度去看這個問題,查詢是否夠快,效率是否穩定,存盤資料多少,以及查找磁盤次數,為什么不是普通二叉樹,為什么不是平衡二叉樹,為什么不是B樹,而偏偏是 B+ 樹呢?
(1)為什么不是普通二叉樹?
如果二叉樹特殊化為一個鏈表,相當于全表掃描,平衡二叉樹相比于二叉查找樹來說,查找效率更穩定,總體的查找速度也更快,
(2)為什么不是平衡二叉樹呢?
我們知道,在記憶體比在磁盤的資料,查詢效率快得多,如果樹這種資料結構作為索引,那我們每查找一次資料就需要從磁盤中讀取一個節點,也就是我們說的一個磁盤塊,但是平衡二叉樹可是每個節點只存盤一個鍵值和資料的,如果是B樹,可以存盤更多的節點資料,樹的高度也會降低,因此讀取磁盤的次數就降下來啦,查詢效率就快啦,
(3)為什么不是 B 樹而是 B+ 樹呢?
B+ 樹非葉子節點上是不存盤資料的,僅存盤鍵值,而B樹節點中不僅存盤鍵值,也會存盤資料,innodb中頁的默認大小是16KB,如果不存盤資料,那么就會存盤更多的鍵值,相應的樹的階數(節點的子節點樹)就會更大,樹就會更矮更胖,如此一來我們查找資料進行磁盤的IO次數有會再次減少,資料查詢的效率也會更快,
B+ 樹索引的所有資料均存盤在葉子節點,而且資料是按照順序排列的,鏈表連著的,那么 B+ 樹使得范圍查找,排序查找,分組查找以及去重查找變得例外簡單,
Hash 索引和 B+ 樹索引區別是什么?你在設計索引是怎么抉擇的?
-
B+ 樹可以進行范圍查詢,Hash 索引不能,
-
B+ 樹支持聯合索引的最左側原則,Hash 索引不支持,
-
B+ 樹支持 order by 排序,Hash 索引不支持,
-
Hash 索引在等值查詢上比 B+ 樹效率更高,
-
B+ 樹使用 like 進行模糊查詢的時候,like 后面(比如%開頭)的話可以起到優化的作用,Hash 索引根本無法進行模糊查詢,
什么是最左前綴原則?什么是最左匹配原則?
最左前綴原則,就是最左優先,在創建多列索引時,要根據業務需求,where 子句中使用最頻繁的一列放在最左邊,
當我們創建一個組合索引的時候,如 (a1,a2,a3),相當于創建了(a1)、(a1,a2)和(a1,a2,a3)三個索引,這就是最左匹配原則,
索引不適合哪些場景?
-
資料量少的不適合加索引
-
更新比較頻繁的也不適合加索引 = 區分度低的欄位不適合加索引(如性別)
索引有哪些優缺點?
(1) 優點:
-
唯一索引可以保證資料庫表中每一行的資料的唯一性
-
索引可以加快資料查詢速度,減少查詢時間
(2)缺點:
-
創建索引和維護索引要耗費時間
-
索引需要占物理空間,除了資料表占用資料空間之外,每一個索引還要占用一定的物理空間
-
以表中的資料進行增、刪、改的時候,索引也要動態的維護,
鎖
MySQL 遇到過死鎖問題嗎,你是如何解決的?
遇到過,我排查死鎖的一般步驟是醬紫的:
(1)查看死鎖日志 show engine innodb status; (2)找出死鎖Sql (3)分析sql加鎖情況 (4)模擬死鎖案發 (5)分析死鎖日志 (6)分析死鎖結果
說說資料庫的樂觀鎖和悲觀鎖是什么以及它們的區別?
(1)悲觀鎖:
悲觀鎖她專一且缺乏安全感了,她的心只屬于當前事務,每時每刻都擔心著它心愛的資料可能被別的事務修改,所以一個事務擁有(獲得)悲觀鎖后,其他任何事務都不能對資料進行修改啦,只能等待鎖被釋放才可以執行,
(2)樂觀鎖:
樂觀鎖的“樂觀情緒”體現在,它認為資料的變動不會太頻繁,因此,它允許多個事務同時對資料進行變動,
實作方式:樂觀鎖一般會使用版本號機制或CAS演算法實作,
MVCC 熟悉嗎,知道它的底層原理?
MVCC (Multiversion Concurrency Control),即多版本并發控制技術,
MVCC在MySQL InnoDB中的實作主要是為了提高資料庫并發性能,用更好的方式去處理讀-寫沖突,做到即使有讀寫沖突時,也能做到不加鎖,非阻塞并發讀,
事務
MySQL事務得四大特性以及實作原理
-
原子性: 事務作為一個整體被執行,包含在其中的對資料庫的操作要么全部被執行,要么都不執行,
-
一致性: 指在事務開始之前和事務結束以后,資料不會被破壞,假如A賬戶給B賬戶轉10塊錢,不管成功與否,A和B的總金額是不變的,
-
隔離性: 多個事務并發訪問時,事務之間是相互隔離的,即一個事務不影響其它事務運行效果,簡言之,就是事務之間是進水不犯河水的,
-
持久性: 表示事務完成以后,該事務對資料庫所作的操作更改,將持久地保存在資料庫之中,
事務的隔離級別有哪些?MySQL的默認隔離級別是什么?
-
讀未提交(Read Uncommitted)
-
讀已提交(Read Committed)
-
可重復讀(Repeatable Read)
-
串行化(Serializable)
Mysql默認的事務隔離級別是可重復讀(Repeatable Read)
什么是幻讀,臟讀,不可重復讀呢?
事務A、B交替執行,事務A被事務B干擾到了,因為事務A讀取到事務B未提交的資料,這就是臟讀,
在一個事務范圍內,兩個相同的查詢,讀取同一條記錄,卻回傳了不同的資料,這就是不可重復讀,
事務A查詢一個范圍的結果集,另一個并發事務B往這個范圍中插入/洗掉了資料,并靜悄悄地提交,然后事務A再次查詢相同的范圍,兩次讀取得到的結果集不一樣了,這就是幻讀,
實戰
MySQL資料庫cpu飆升的話,要怎么處理呢?
排查程序:
(1)使用top 命令觀察,確定是mysqld導致還是其他原因, (2)如果是mysqld導致的,show processlist,查看session情況,確定是不是有消耗資源的sql在運行, (3)找出消耗高的 sql,看看執行計劃是否準確, 索引是否缺失,資料量是否太大,
處理:
(1)kill 掉這些執行緒(同時觀察 cpu 使用率是否下降), (2)進行相應的調整(比如說加索引、改 sql、改記憶體引數) (3)重新跑這些 SQL,
其他情況:
也有可能是每個 sql 消耗資源并不多,但是突然之間,有大量的 session 連進來導致 cpu 飆升,這種情況就需要跟應用一起來分析為何連接數會激增,再做出相應的調整,比如說限制連接數等
MYSQL的主從延遲,你怎么解決?
主從復制分了五個步驟進行:
-
步驟一:主庫的更新事件(update、insert、delete)被寫到binlog
-
步驟二:從庫發起連接,連接到主庫,
-
步驟三:此時主庫創建一個binlog dump thread,把binlog的內容發送到從庫,
-
步驟四:從庫啟動之后,創建一個I/O執行緒,讀取主庫傳過來的binlog內容并寫入到relay log
-
步驟五:還會創建一個SQL執行緒,從relay log里面讀取內容,從Exec_Master_Log_Pos位置開始執行讀取到的更新事件,將更新內容寫入到slave的db
主從同步延遲的原因
一個服務器開放N個鏈接給客戶端來連接的,這樣有會有大并發的更新操作, 但是從服務器的里面讀取binlog的執行緒僅有一個,當某個SQL在從服務器上執行的時間稍長 或者由于某個SQL要進行鎖表就會導致,主服務器的SQL大量積壓,未被同步到從服務器里,這就導致了主從不一致, 也就是主從延遲,
主從同步延遲的解決辦法
-
主服務器要負責更新操作,對安全性的要求比從服務器要高,所以有些設定引數可以修改,比如sync_binlog=1,innodb_flush_log_at_trx_commit = 1 之類的設定等,
-
選擇更好的硬體設備作為slave,
-
把一臺從服務器當度作為備份使用, 而不提供查詢, 那邊他的負載下來了, 執行relay log 里面的SQL效率自然就高了,
-
增加從服務器嘍,這個目的還是分散讀的壓力,從而降低服務器負載,
如果讓你做分庫與分表的設計,簡單說說你會怎么做?
分庫分表方案:
-
水平分庫:以欄位為依據,按照一定策略(hash、range等),將一個庫中的資料拆分到多個庫中,
-
水平分表:以欄位為依據,按照一定策略(hash、range等),將一個表中的資料拆分到多個表中,
-
垂直分庫:以表為依據,按照業務歸屬不同,將不同的表拆分到不同的庫中,
-
垂直分表:以欄位為依據,按照欄位的活躍性,將表中欄位拆到不同的表(主表和擴展表)中,
常用的分庫分表中間件:
-
sharding-jdbc
-
Mycat
分庫分表可能遇到的問題
-
事務問題:需要用分布式事務啦
-
跨節點Join的問題:解決這一問題可以分兩次查詢實作
-
跨節點的count,order by,group by以及聚合函式問題:分別在各個節點上得到結果后在應用程式端進行合并,
-
資料遷移,容量規劃,擴容等問題
-
ID問題:資料庫被切分后,不能再依賴資料庫自身的主鍵生成機制啦,最簡單可以考慮UUID
-
跨分片的排序分頁問題
好了,奪命 20 問看完了,你能全部接住嗎?
另外我把大學和作業中用的經典電子書庫(包含資料結構、作業系統、C++/C、網路經典、前端編程經典、Java相關、程式員認知、職場發展)、面試找作業的資料匯總都打包放在這了,這套資源可不是一般那種網上找的資源,是伴隨我從學生一路到職場,非常寶貴!
已經打包好了:保姆級整理,進大廠前必看的經典編程書單(含下載方式)

最后:
大家學會了嗎?收藏等于白嫖,點贊才是真愛,雷小帥感謝大家~~~
作者:雷小帥
推薦一個Github 開源專案,『Java八股文』Java面試套路,領取 10G 免費學習資料,Java進階學習,打破內卷拿大廠Offer,升職加薪!
作者簡介:
?讀過幾年書:華中科技大學碩士畢業;
😂浪過幾個大廠:華為、網易、百度……
😘一直堅信技術能改變世界,愿保持初心,加油技術人!微信搜索公眾號【愛笑的架構師】,關注這個對技術有追求且有趣的打工人,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/289566.html
標籤:java
上一篇:【2021軟體創新實驗室暑假集訓】JDBC(原理、使用以及實作簡單的資料庫連接池)
下一篇:java入門-----運算子
