噓,別著急,Java研發崗面試複盤總

程序員小李子 2021-09-20 03:59:20 阅读数:496

java

返回有一列叫“type”,常見取值有:
ALL、index、range、 ref、eq_ref、const、system、NULL(從左到右,性能從差到好)
ALL 代錶這條 SQL 語句全錶掃描了,需要優化。一般來說需要達到range 級別及以上。
# 錶結構優化
以一個場景舉例說明:
“user”錶中有 user_id、nickname 等字段,“order”錶中有order_id、user_id等字段,如果想拿到用戶昵稱怎麼辦?一般情况是通過 join 關聯錶操作,在查詢訂單錶時關聯查詢用戶錶,從而獲取到用戶昵稱。
但是隨著業務量增加,訂單錶和用戶錶肯定也是暴增,這時候通過兩個錶關聯數據就比較費力了,為了取一個昵稱字段而不得不關聯查詢幾十上百萬的用戶錶,其速度可想而知。
這個時候可以嘗試將 nickname 這個字段加到 order 錶中(order_id、user_id、nickname),這種做法通常叫做數據庫錶冗餘字段。這樣做的好處展示訂單列錶時不需要再關聯查詢用戶錶了。
冗餘字段的做法也有一個弊端,如果這個字段更新會同時涉及到多個錶的更新,因此在選擇冗餘字段時要盡量選擇不經常更新的字段。
# 架構優化
當單臺數據庫實例扛不住,我們可以增加實例組成集群對外服務。
當發現讀請求明顯多於寫請求時,我們可以讓主實例負責寫,從實例對外提供讀的能力;
如果讀實例壓力依然很大,可以在數據庫前面加入緩存如 redis,讓請求優先從緩存取數據减少數據庫訪問。
緩存分擔了部分壓力後,數據庫依然是瓶頸,這個時候就可以考慮分庫分錶的方案了,後面會詳細介紹。
# 硬件優化
硬件成本非常高,一般來說不可能遇到數據庫性能瓶頸就去昇級硬件。
在前期業務量比較小的時候,昇級硬件數據庫性能可以得到較大提昇;但是在後期,昇級硬件得到的收益就不那麼明顯了。
# 分庫分錶詳解
下面我們以一個商城系統為例逐步講解數據庫是如何一步步演進。
# 單應用單數據庫
在早期創業階段想做一個商城系統,基本就是一個系統包含多個基礎功能模塊,最後打包成一個 war 包部署,這就是典型的單體架構應用。
![噓,別著急,Java研發崗面試複盤總_後端](https://s6.51cto.com/images/20210920/1632080996815060.jpg)
如上圖,商城系統包括主頁 Portal 模板、用戶模塊、訂單模塊、庫存模塊等,所有的模塊都共有一個數據庫,通常數據庫中有非常多的錶。
因為用戶量不大,這樣的架構在早期完全適用,開發者可以拿著 demo到處找(騙)投資人。
一旦拿到投資人的錢,業務就要開始大規模推廣,同時系統架構也要匹配業務的快速發展。
# 多應用單數據庫
在前期為了搶占市場,這一套系統不停地迭代更新,代碼量越來越大,架構也變得越來越臃腫,現在隨著系統訪問壓力逐漸增加,系統拆分就勢在必行了。
為了保證業務平滑,系統架構重構也是分了幾個階段進行。
第一個階段將商城系統單體架構按照功能模塊拆分為子服務,比如:Portal 服務、用戶服務、訂單服務、庫存服務等。
![噓,別著急,Java研發崗面試複盤總_後端_02](https://s9.51cto.com/images/20210920/1632080996993979.jpg)
如上圖,多個服務共享一個數據庫,這樣做的目的是底層數據庫訪問邏輯可以不用動,將影響降到最低。
# 多應用多數據庫
隨著業務推廣力度加大,數據庫終於成為了瓶頸,這個時候多個服務共享一個數據庫基本不可行了。我們需要將每個服務相關的錶拆出來單獨建立一個數據庫,這其實就是“分庫”了。
單數據庫的能够支撐的並發量是有限的,拆成多個庫可以使服務間不用競爭,提昇服務的性能。
![噓,別著急,Java研發崗面試複盤總_Java_03](https://s8.51cto.com/images/20210920/1632080997880444.jpg)
如上圖,從一個大的數據中分出多個小的數據庫,每個服務都對應一個數據庫,這就是系統發展到一定階段必要要做的“分庫”操作。
現在非常火的微服務架構也是一樣的,如果只拆分應用不拆分數據庫,不能解决根本問題,整個系統也很容易達到瓶頸。
# 分錶
說完了分庫,那什麼時候分錶呢?
如果系統處於高速發展階段,拿商城系統來說,一天下單量可能幾十萬,那數據庫中的訂單錶增長就特別快,增長到一定階段數據庫查詢效率就會出現明顯下降。
因此,當單錶數據增量過快,業界流傳是超過500萬的數據量就要考慮分錶了。當然500萬只是一個經驗值,大家可以根據實際情况做出决策。
那如何分錶呢?
分錶有幾個維度,一是水平切分和垂直切分,二是單庫內分錶和多庫內分錶。
**水平拆分和垂直拆分**
就拿用戶錶(user)來說,錶中有7個字段:id,name,age,sex,nickname,description,如果 nickname 和 description 不常用,我們可以將其拆分為另外一張錶:用戶詳細信息錶,這樣就由一張用戶錶拆分為了用戶基本信息錶+用戶詳細信息錶,兩張錶結構不一樣相互獨立。但是從這個角度來看垂直拆分並沒有從根本上解决單錶數據量過大的問題,因此我們還是需要做一次水平拆分。
![噓,別著急,Java研發崗面試複盤總_程序員_04](https://s5.51cto.com/images/20210920/1632080997897180.jpg)
還有一種拆分方法,比如錶中有一萬條數據,我們拆分為兩張錶,id 為奇數的:1,3,5,7……放在 user1, id 為偶數的:2,4,6,8……放在 user2中,這樣的拆分辦法就是水平拆分了。
水平拆分的方式也很多,除了上面說的按照 id 拆錶,還可以按照時間維度去拆分,比如訂單錶,可以按每日、每月等進行拆分。
* 每日錶:只存儲當天的數據。
* 每月錶:可以起一個定時任務將前一天的數據全部遷移到當月錶。
* 曆史錶:同樣可以用定時任務把時間超過 30 天的數據遷移到 history錶。
總結一下水平拆分和垂直拆分的特點:
* 垂直切分:基於錶或字段劃分,錶結構不同。
* 水平切分:基於數據劃分,錶結構相同,數據不同。
**單庫內拆分和多庫拆分**
拿水平拆分為例,每張錶都拆分為了多個子錶,多個子錶存在於同一數據庫中。比如下面用戶錶拆分為用戶1錶、用戶2錶。
![噓,別著急,Java研發崗面試複盤總_後端_05](https://s5.51cto.com/images/20210920/1632080997230573.jpg)
在一個數據庫中將一張錶拆分為幾個子錶在一定程度上可以解决單錶查詢性能的問題,但是也會遇到一個問題:單數據庫存儲瓶頸。
所以在業界用的更多的還是將子錶拆分到多個數據庫中。比如下圖中,用戶錶拆分為兩個子錶,兩個子錶分別存在於不同的數據庫中。
![噓,別著急,Java研發崗面試複盤總_程序員_06](https://s4.51cto.com/images/20210920/1632080997456493.jpg)
# **學習分享,共勉**
這裏是小編拿到的學習資源,其中包括“中高級Java開發面試高頻考點題筆記300道.pdf”和“Java核心知識體系筆記.pdf”文件分享,內容豐富,**囊括了JVM、鎖、並發、Java反射、Spring原理、微服務、Zookeeper、數據庫、數據結構等大量知識點。同時還有Java進階學習的知識筆記腦圖(內含大量學習筆記)!**
> **資料整理不易,讀者朋友可以轉發分享下!**
**[CodeChina開源項目:【一線大廠Java面試題解析+核心總結學習筆記+最新講解視頻】](https://ali1024.coding.net/public/P7/Java/git)**
**Java核心知識體系筆記.pdf**
![噓,別著急,Java研發崗面試複盤總_Java_07](https://s6.51cto.com/images/20210920/1632080997850307.jpg)
**中高級Java開發面試高頻考點題筆記300道.pdf**
![噓,別著急,Java研發崗面試複盤總_後端_08](https://s7.51cto.com/images/20210920/1632080998806260.jpg)
**架構進階面試專題及架構學習筆記腦圖**
![噓,別著急,Java研發崗面試複盤總_程序員_09](https://s6.51cto.com/images/20210920/1632080998936940.jpg)
**Java架構進階學習視頻分享**

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
版权声明:本文为[程序員小李子]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210920035919532k.html