今天我將那些騰訊面試過的 MySQL 場景問題給大家整理出來,本文將跟大家一起來探討如何回答這些問題。
1.一個 6 億的表 a,一個 3 億的表 b,通過外間 tid 關聯,你如何最快的查詢出滿足條件的第 50000 到第 50200 中的這 200 條數據記錄?
2.一條 sql 執行過長的時間,你如何優化,從哪些方面入手?
3.索引已經建好了,那我再插入一條數據,索引會有哪些變化?
4.mysql 的是怎麼解決併發問題的?
5.MySQL 兩個線程的 update 語句同時處理一條數據,會不會有阻塞?
6.兩條 update 語句處理一張表的不同的主鍵範圍的記錄,一個 < 10,另一個 > 15,會不會遇到阻塞?
7.如果 Explain 用到的索引不正確的話,有什麼辦法干預嗎?
8.給你張表,發現查詢速度很慢,你有哪些解決方案?
9.關心過業務系統裏面的 sql 耗時嗎?統計過慢查詢嗎?對慢查詢都怎麼優化過?(explain)?
一個 6 億的表 a,一個 3 億的表 b,通過外間 tid 關聯,你如何最快的查詢出滿足條件的第 50000 到第 50200 中的這 200 條數據記錄?
這是一道騰訊的面試題,其實這個問題和上面是同一個問題,都是超大分頁的問題,這就像讀書的時候做數學題一樣,上面是公式、定理,下面是題目,所以要學會舉一反三。
- 如果 A 表 TID 是自增長,並且是連續的,B 表的 ID 為索引
select * from a,b where a.tid = b.id and a.tid>500000 limit 200;
- 如果 A 表的 TID 不是連續的,那麼就需要使用覆蓋索引.TID 要麼是主鍵,要麼是輔助索引,B 表 ID 也需要有索引。
select * from b , (select tid from a limit 50000,200) a where b.id = a .tid;
一條 sql 執行過長的時間,你如何優化,從哪些方面入手?
查看是否涉及多表和子查詢,優化 Sql 結構,如去除冗餘字段,是否可拆表等
優化索引結構,看是否可以適當添加索引
數量大的表,可以考慮進行分離/分表(如交易流水錶)
數據庫主從分離,讀寫分離
explain 分析 sql 語句,查看執行計劃,優化 sql
查看 Mysql 執行日誌,分析是否有其他方面的問題
索引已經建好了,那我再插入一條數據,索引會有哪些變化?
插入新數據可能導致 B+樹結構的調整和索引信息的更新,以保持 B+樹的平衡性和正確性,這些變化通常由數據庫系統自動處理,確保數據的一致性和索引的有效性。
如果插入的數據導致葉子節點已滿,可能會觸發葉子節點的分裂操作,以保持 B+樹的平衡性。
mysql 的是怎麼解決併發問題的?
鎖機制:Mysql 提供了多種鎖機制來保證數據的一致性,包括行級鎖、表級鎖、頁級鎖等。通過鎖機制,可以在讀寫操作時對數據進行加鎖,確保同時只有一個操作能夠訪問或修改數據。
事務隔離級別:Mysql 提供了多種事務隔離級別,包括讀未提交、讀已提交、可重複讀和串行化。通過設置合適的事務隔離級別,可以在多個事務併發執行時,控制事務之間的隔離程度,以避免數據不一致的問題。
MVCC(多版本併發控制):Mysql 使用 MVCC 來管理併發訪問,它通過在數據庫中保存不同版本的數據來實現不同事務之間的隔離。在讀取數據時,Mysql 會根據事務的隔離級別來選擇合適的數據版本,從而保證數據的一致性。
MySQL 兩個線程的 update 語句同時處理一條數據,會不會有阻塞?
如果是兩個事務同時更新了 id = 1,比如 update ... where id = 1,那麼是會阻塞的。因為 InnoDB 存儲引擎實現了行級鎖。
當 A 事務對 id =1 這行記錄進行更新時,會對主鍵 id 為 1 的記錄加 X 類型的記錄鎖,這樣第二事務對 id = 1 進行更新時,發現已經有記錄鎖了,就會陷入阻塞狀態。
兩條 update 語句處理一張表的不同的主鍵範圍的記錄,一個 < 10,另一個 > 15,會不會遇到阻塞?
不會,因為鎖住的範圍不一樣,不會形成衝突。(當然前提是,沒有其他事務干預 且 使用索引沒有進行全表掃描)
第一條 update sql 的話( id<10),鎖住的範圍是(-♾️,10);
第二條 update sql 的話(id >15),鎖住的範圍是(15,+♾️)。
追加問題,如果 2 個範圍不是主鍵或索引?還會阻塞嗎?
如果 2 個範圍查詢的字段不是索引的話,那就代表 update 沒有用到索引,這時候觸發了全表掃描,全部索引都會加行級鎖,這時候第二條 update 執行的時候,就會阻塞了。
因為如果 update 沒有用到索引,在掃描過程中會對索引加鎖,所以全表掃描的場景下,所有記錄都會被加鎖,也就是這條 update 語句產生了 4 個記錄鎖和 5 個間隙鎖,相當於鎖住了全表。
如果 Explain 用到的索引不正確的話,有什麼辦法干預嗎?
可以使用 force index,強制走索引。
explain select name,price
from products
force index (idx_price)
where price between 10 and 80
orderby by price;
給你張表,發現查詢速度很慢,你有哪些解決方案?
如果面試遇到了這樣相似的問題,如優化查詢速度,可以選擇下面的幾條來回答。
分析查詢語句:使用 explain 命令分析 sql 執行計劃,找出慢查詢的原因,比如是否使用了全表掃描,是否存在索引未被使用的情況等,並根據相應情況對索引進行適當修改。
創建或優化索引:根據查詢條件創建合適的索引,特別是經常用於 where 子句的字段、orderby 排序字段、join 連表查詢的字典、group by 的字段,並且如果查詢中經常涉及多個字段,考慮創建聯合索引,使用聯合索引要符合最左匹配原則,不然會索引失效
避免索引失效:比如不要用左模糊匹配、函數計算、表達式計算等等
查詢優化:避免使用 select *,只查詢真正需要的列;使用覆蓋索引,即索引包含所有查詢的字段;連表查詢最好要以小表驅動大表,並且被驅動表的字段要有索引,當然最好通過冗餘字段的設計,彼岸連表查詢。
分頁優化:針對 limit n,m 深分頁的查詢優化,可以把 limit 查詢轉換成某個位置的查詢:select * from product where id> 20000 limit 10 ,該方案適用於主鍵自增的表
優化數據庫表:如果單表的數據超過了千萬級別,考慮是否需要將大表拆分為小表,減輕單個表的查詢壓力。也可以將字段多的表分解成多個表,有些字段使用頻率高,有些低,數據量大時,會由於使用頻率低的存在而變慢,可以考慮分開。
使用緩存技術:引入緩存層,如 redis,存儲熱點數據和頻繁查詢的結果,但是考慮緩存一致性的問題,對於讀請求會選擇旁路緩存策略,對於寫請求會選擇先更新數據庫,再刪除緩存的策略。
關心過業務系統裏面的 sql 耗時嗎?統計過慢查詢嗎?對慢查詢都怎麼優化過?(explain)?
在業務系統中,除了使用主鍵進行的查詢,其他的我都會在測試庫上測試其耗時,慢查詢的統計主要由運維在做,會定期將業務中的慢查詢反饋給我們。
慢查詢的優化首先要搞明白慢的原因是什麼? 是查詢條件沒有命中索引?是 load 了不需要的數據列?還是數據量太大?
所以優化也是針對這三個方向來的,
首先分析語句,看看是否 load 了額外的數據,可能是查詢了多餘的行並且拋棄掉了,可能是加載了許多結果中並不需要的列,對語句進行分析以及重寫。
分析語句的執行計劃(explain),然後獲得其使用索引的情況,之後修改語句或者修改索引,使得語句可以儘可能的命中索引。
如果對語句的優化已經無法進行,可以考慮表中的數據量是否太大,如果是的話可以進行橫向或者縱向的分表。
就業陪跑訓練營學員投稿
歡迎關注 ❤
我們搞了一個免費的面試真題共享羣,互通有無,一起刷題進步。
沒準能讓你能刷到自己意向公司的最新面試題呢。
感興趣的朋友們可以加我微信:wangzhongyang1993,備註:面試羣。