自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

杭州某大廠:MySQL 連環(huán)問

數(shù)據(jù)庫(kù) MySQL
隨著用戶量的激增和時(shí)間的堆砌,存在數(shù)據(jù)庫(kù)里面的數(shù)據(jù)越來越多,此時(shí)的數(shù)據(jù)庫(kù)就會(huì)產(chǎn)生瓶頸,出現(xiàn)資源報(bào)警、查詢慢等場(chǎng)景。

[[395970]]

本文轉(zhuǎn)載自微信公眾號(hào)「yes的練級(jí)攻略」,作者是Yes呀 。轉(zhuǎn)載本文請(qǐng)聯(lián)系yes的練級(jí)攻略公眾號(hào)。

大家好,我是yes。

MySQL 面試題又更新啦!

請(qǐng)繼續(xù)接招。

說說分庫(kù)分表?

隨著用戶量的激增和時(shí)間的堆砌,存在數(shù)據(jù)庫(kù)里面的數(shù)據(jù)越來越多,此時(shí)的數(shù)據(jù)庫(kù)就會(huì)產(chǎn)生瓶頸,出現(xiàn)資源報(bào)警、查詢慢等場(chǎng)景。

首先單機(jī)數(shù)據(jù)庫(kù)所能承載的連接數(shù)、I/O及網(wǎng)絡(luò)的吞吐等都是有限的,所以當(dāng)并發(fā)量上來了之后,數(shù)據(jù)庫(kù)就漸漸頂不住了。

再則,如果單表的數(shù)據(jù)量過大,查詢的性能也會(huì)下降。因?yàn)閿?shù)據(jù)越多 B+ 樹就越高,樹越高則查詢 I/O 的次數(shù)就越多,那么性能也就越差。

因?yàn)樯鲜龅脑?,不得已就得上分?kù)分表了。

把以前存在一個(gè)數(shù)據(jù)庫(kù)實(shí)例里的數(shù)據(jù)拆分成多個(gè)數(shù)據(jù)庫(kù)實(shí)例,部署在不同的服務(wù)器中,這是分庫(kù)。

把以前存在一張表里面的數(shù)據(jù)拆分成多張表,這是分表。

一般而言:

  • 分表:是為了解決由于單張表數(shù)據(jù)量多大,而導(dǎo)致查詢慢的問題。大致三、四千萬行數(shù)據(jù)就得拆分,不過具體還是得看每一行的數(shù)據(jù)量大小,有些字段都很小的可能支持更多行數(shù),有些字段大的可能一千萬就頂不住了。
  • 分庫(kù):是為了解決服務(wù)器資源受單機(jī)限制,頂不住高并發(fā)訪問的問題,把請(qǐng)求分配到多臺(tái)服務(wù)器上,降低服務(wù)器壓力。

你們一般怎么分庫(kù)的?

一般分庫(kù)都是按照業(yè)務(wù)劃分的,比如訂單庫(kù)、用戶庫(kù)等等。

有時(shí)候會(huì)針對(duì)一些特殊的庫(kù)再作切分,比如一些活動(dòng)相關(guān)的庫(kù)都做了拆分。

因?yàn)樽龌顒?dòng)的時(shí)候并發(fā)可能會(huì)比較高,怕影響現(xiàn)有的核心業(yè)務(wù),所以即使有關(guān)聯(lián),也會(huì)單獨(dú)做拆分。

那你覺得分庫(kù)會(huì)帶來什么問題呢?

首先是事務(wù)的問題。

我們使用關(guān)系型數(shù)據(jù)庫(kù),有很大一點(diǎn)在于它保證事務(wù)完整性。

而分庫(kù)之后單機(jī)事務(wù)就用不上了,必須使用分布式事務(wù)來解決,而分布式事務(wù)基本的都是殘缺的(我之前文章把分布式事務(wù)匯總了一波,后臺(tái)搜索分布式事務(wù)就有了)。

這是很重要的一點(diǎn)需要考慮。

  • 連表 JOIN 問題

在一個(gè)庫(kù)中的時(shí)候我們還可以利用 JOIN 來連表查詢,而跨庫(kù)了之后就無法使用 JOIN 了。

此時(shí)的解決方案就是在業(yè)務(wù)代碼中進(jìn)行關(guān)聯(lián),也就是先把一個(gè)表的數(shù)據(jù)查出來,然后通過得到的結(jié)果再去查另一張表,然后利用代碼來關(guān)聯(lián)得到最終的結(jié)果。

這種方式實(shí)現(xiàn)起來稍微比較復(fù)雜,不過也是可以接受的。

還有可以適當(dāng)?shù)娜哂嘁恍┳侄?。比如以前的表就存?chǔ)一個(gè)關(guān)聯(lián) ID,但是業(yè)務(wù)時(shí)常要求返回對(duì)應(yīng)的 Name 或者其他字段。這時(shí)候就可以把這些字段冗余到當(dāng)前表中,來去除需要關(guān)聯(lián)的操作。

那你們?cè)趺捶直淼?

分表其實(shí)有兩種:

  • 垂直分表
  • 水平分表

垂直分表,來看個(gè)圖,很直觀:

垂直分表就是把一些不常用的大字段剝離出去。

像上面的例子:用戶名是很常見的搜索結(jié)果,性別和年齡占用的空間又不大,而地址和個(gè)人簡(jiǎn)介占用的空間相對(duì)而言就較大,我們都知道一個(gè)數(shù)據(jù)頁(yè)的空間是有限的,把一些無用的數(shù)據(jù)拆分出去,一頁(yè)就能存放更多行的數(shù)據(jù)。

內(nèi)存存放更多有用的數(shù)據(jù),就減少了磁盤的訪問次數(shù),性能就得到提升。

水平分表,則是因?yàn)橐粡埍韮?nèi)的數(shù)據(jù)太多了,上文也提到了數(shù)據(jù)越多 B+ 樹就越高,訪問的性能就差,所以進(jìn)行水平拆分。

其實(shí)不管這些,淺顯的理解下,在一百個(gè)數(shù)據(jù)里面找一個(gè)數(shù)據(jù)快,還是在一萬個(gè)數(shù)據(jù)里面找一個(gè)數(shù)據(jù)快?

即使有索引,那厚的書目錄多,翻目錄也慢~

那分表會(huì)有什么問題?

垂直分表還好,就是需要關(guān)聯(lián)一下,而水平分表就有點(diǎn)麻煩了。

  • 排序、count、分頁(yè)問題

如果一個(gè)用戶的數(shù)據(jù)被拆分到多個(gè)表中,那查詢結(jié)果分頁(yè)就不像以前單張表那樣直接就能查出來了,像 count 操作也是一樣的。

只能由業(yè)務(wù)代碼來實(shí)現(xiàn)或者用中間件將各表中的數(shù)據(jù)匯總、排序、分頁(yè)然后返回。

像 count 操作的結(jié)果其實(shí)可以緩存下來,然后每次數(shù)據(jù)增刪都更新計(jì)數(shù)。

  • 路由問題

分表的路由可以分:

  • Hash 路由
  • 范圍路由
  • 路由表

Hash 路由,其實(shí)就是選擇表中的某一列,然后進(jìn)行 Hash 運(yùn)算,將 Hash 運(yùn)算得到的結(jié)果再對(duì)子表數(shù)進(jìn)行取模,這樣就能均勻的將數(shù)據(jù)分到不同的子表上。

這跟 HashMap 選哪個(gè)桶是一樣的原理。

優(yōu)點(diǎn)就是數(shù)據(jù)分布均勻。

缺點(diǎn)就是增加子表的時(shí)候麻煩,想想 HashMap的擴(kuò)容,是不是得搬遷數(shù)據(jù)?這個(gè)分表也是一樣的,我們可都知道,數(shù)據(jù)遷移一件麻煩事!

范圍路由,其實(shí)很簡(jiǎn)單,可以是時(shí)間,也可以是地址,表示一定的范圍的即可。

比如本來一張 User 表,我可以分 User_HZ、User_BJ、User_SH,按照地名來劃分 User。

再比如 log 表,我可以將表分為 log_202103、 log_202104,把日志按照年月來劃分。

優(yōu)點(diǎn)就是相對(duì)而言比較容易擴(kuò)展,比如現(xiàn)在來個(gè) GZ,那就加個(gè) User_GZ。如果到了 5 月,那就建個(gè) log_202105。

缺點(diǎn)就是數(shù)據(jù)可能分布不均勻,例如 BJ 的用戶特別多或者某個(gè)月搞了促銷,日志量特別大,等等。

路由表,就是專門搞個(gè)表來記錄路由信息,來看個(gè)圖就很清楚了。

從圖中我們就能得知,UserID 為 2 的用戶數(shù)據(jù)在要去 User_3 這個(gè)用戶表查詢。

優(yōu)點(diǎn)就是靈活咯,如果要遷移數(shù)據(jù),直接遷移然后路由表一改就完事兒了~

缺點(diǎn)就是得多查一次,每次查詢都需要訪問路由表,不過這個(gè)一般會(huì)做緩存的。

  • 全局主鍵問題

以前單表的時(shí)候很簡(jiǎn)單,就是主鍵自增,現(xiàn)在分表了之后就有點(diǎn)尷尬了。

所以需要一些手段來保證全局主鍵唯一。

還是自增,只不過自增步長(zhǎng)設(shè)置一下。比如現(xiàn)在有三張表,步長(zhǎng)設(shè)置為3,三張表 ID 初始值分別是1、2、3。這樣第一張表的 ID 增長(zhǎng)是 1、4、7。第二張表是2、5、8。第三張表是3、6、9,這樣就不會(huì)重復(fù)了。

UUID,這種最簡(jiǎn)單,但是不連續(xù)的主鍵插入會(huì)導(dǎo)致嚴(yán)重的頁(yè)分裂,性能比較差。

分布式 ID,比較出名的就是 Twitter 開源的 sonwflake 雪花算法,具體就不展開了,不然就又是一篇文章了,簡(jiǎn)單點(diǎn)利用 redis 來遞增也行。

那上面說的路由問題的 Sharding-Key 如何設(shè)計(jì)呢?

我們分表是按照某個(gè)列來拆分的,那個(gè)列就是 Sharding-Key,查詢的時(shí)候必須帶上這個(gè)列才行。

例如上面提到的 log_202103,那表明查詢條件一定得帶上日期,這樣才能找到正確的表。

所以設(shè)計(jì)上得考慮查詢的條件來作為 Sharding-Key。

舉個(gè)常常會(huì)被問的訂單表 Sharding-Key 例子。

你想著查找訂單的時(shí)候會(huì)通過訂單號(hào)去找,所以應(yīng)該利用訂單 ID 來作為 Sharding-Key。

但是你想想,你打開外賣軟件想查找你的歷史訂單的時(shí)候,你是沒有訂單 ID 的,你只有你的 UserID,那此時(shí)只能把所有子表都通過 UserID 遍歷一遍,這樣效率就很低了!

所以你想著那用 UserID 來作為 Sharding-Key 吧!

但是,商家呢?商家肯定關(guān)心自己今天賣了多少單,所以他也要查找訂單,但他只有自己的商家 ID,所以如果要查詢訂單,只能把所有子表都通過商家 ID 遍歷一遍,這樣效率就很低了!

所以 Sharding-Key 是滿足不了所有查詢需求的,只能曲線救國(guó)。

一般做法就是冗余數(shù)據(jù)。

將訂單同步到另一張表中給商家使用,這個(gè)表按商家 ID 來作為 Sharding-Key,也可以將數(shù)據(jù)同步到 ES 中。一般而言這里的數(shù)據(jù)同步都是異步處理,不會(huì)影響正常流程。

最后

今天的面試題主要是分庫(kù)分表相關(guān)的,基本上常問的都涵蓋了。

MySQL 面試題未完,持續(xù)更新~

 

責(zé)任編輯:武曉燕 來源: yes的練級(jí)攻略
相關(guān)推薦

2021-10-26 15:56:57

kafka數(shù)據(jù)平臺(tái),

2023-02-26 02:00:36

OpenFeign接口實(shí)現(xiàn)類

2024-03-13 13:56:11

openFeignHttp服務(wù)調(diào)用

2023-03-08 09:03:55

2023-04-26 09:16:17

2021-11-11 17:34:54

數(shù)據(jù)庫(kù)索引面試

2020-05-14 17:41:40

Redis 6.0多線程數(shù)據(jù)庫(kù)

2021-06-04 14:38:12

網(wǎng)絡(luò)通信TCP揮手

2022-03-25 09:01:36

Spring循環(huán)依賴面試

2021-11-08 14:10:37

分布式Spring鏈路

2019-05-29 15:17:43

TCPHTTPSSL

2021-07-21 09:15:27

MySQL數(shù)據(jù)庫(kù)面試

2023-06-07 15:29:33

MySQL事務(wù)面試

2022-04-01 12:40:13

MySQL數(shù)據(jù)庫(kù)

2015-09-22 20:19:43

2020-09-24 06:39:58

MySQL數(shù)據(jù)庫(kù)

2020-09-08 07:01:01

調(diào)度算法

2021-01-18 08:25:44

Zookeeper面試分布式

2023-01-28 08:24:28

MySQL索引B+樹

2023-04-26 07:40:34

MySQL索引類型存儲(chǔ)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)