多維度分片需求,如何解決查詢問題?

架構擺渡人發表於2022-05-04

大家好,我是【架構擺渡人】,一隻十年的程式猿。這是分庫分表系列的第一篇文章,這個系列會給大家分享很多在實際工作中有用的經驗,如果有收穫,還請分享給更多的朋友。

其實這個系列有錄過視訊給大家學習,但很多讀者反饋說看視訊太慢了。也不好沉澱為文件資料,希望能有一系列文字版本的講解,要用的時候可以快速瀏覽關鍵的知識點。那麼它就來了,我再花點時間寫成幾篇連續的文章供大家學習。

需求背景

單庫單表的時候,我們在實現業務需求的時候,是不會考慮說哪些欄位不能用於查詢,只要表中有的欄位就可以用它來做條件查詢。

當分庫分表後,就必須要要考慮查詢條件中得有哪些欄位。必須要有的肯定是分片的欄位,比如你根據使用者ID進行分片,然後查詢的時候卻沒有使用者ID,這樣就沒辦法知道這條SQL到底要去哪個庫哪個表查詢,只能查詢所有的庫表進行結果的聚合邏輯,效能非常差。

比如我們以訂單來說明,常用的查詢場景有根據訂單號查詢,根據買家查詢訂單,根據賣家查詢訂單。

比如我們以使用者來說明,常用的查詢場景有根據使用者ID查詢,根據使用者名稱查詢,根據手機號碼查詢。

但是大家想一個問題,就是你分表都是根據一個欄位去分的,比如訂單的買家,也就是所有買家的訂單都會在某個庫的某個表中儲存。直接根據買家是可以定位到資料的位置,但是如果直接根據訂單號和賣家去查,是無法定位資料的儲存位置。使用者的查詢也是一樣的問題,這就是我們今天要講的內容。

實現方式

對映表方式

目前查詢訂單有三個場景,分別是買家,訂單號,賣家或者店鋪。分表欄位的選擇肯定是優先選擇查詢量最大的場景進行分片,所以訂單最適合的分片欄位就是買家。

那現在要根據訂單號和賣家去查詢訂單使用對映表的方式該如何實現呢?

對映表其實就是單獨為賣家和訂單號建立一個對映關係,當我們通過訂單號取查詢的時候,先通過對映關係找到訂單號對應的買家,然後再通過買家就能找到資料的儲存位置了。

對映可以用普通的表進行儲存,也可以用KV的Nosql儲存。

二級索引

索引的方式其實跟對映差不多,不同的點在於對映是一一對應的,而索引方式是一對多的場景。

也就是說我們將買家,賣家,訂單號都儲存起來,這個儲存可以用ES,因為ES天生就支援水平擴充套件,能否儲存大資料量。

要注意的是這裡只是儲存要搜尋的條件,所以是沒辦法替代資料庫的分庫分表。

那麼怎麼去構建這個索引呢?可以採用程式碼的方式,直接在資料建立的時候往索引裡面寫一份,也可以基於binlog的方式,去構建,這樣耦合度更低,資料儲存稍微有點延遲。

有了這個索引之後,比如根據訂單號去查詢的時候,就直接先查索引,得到買家,再去查詢原始資料。賣家的查詢也是一樣的邏輯。

融合方式

比如根據訂單號去查詢,無論是通過對映還是索引的方式,都需要一次查詢操作。如果我們能直接通過訂單號就知道這個訂單號是哪個買家的,這樣就不用多出一次查詢操作了呀。

所以我們可以在訂單號裡面融入買家的資訊,一般訂單號都比較長,大家可以去看看自己淘寶的訂單號,是不是能發現什麼規律,比如前幾位是固定的,或者後幾位是固定的,講到這裡大家都懂了吧。

把買家融入到訂單號裡面後,查詢的時候就可以直接提取出買家,完美的省掉了一次多餘的查詢操作。

空間換時間

通過融合方式,我們完美的避免了多一次查詢的操作,但是這種方式也只適用於某一類查詢,比如買家和訂單號的查詢。如果要根據賣家查呢?還是得涉及到轉換的問題,根據賣家拿到買家,然後查詢。

在設計表欄位的時候,我們為了避免聯合查詢,通常也會多加一個欄位進行冗餘儲存,這其實就是空間換時間的概念。

同樣在這個場景下,我們也可以用空間換時間的方式來解決,賣家維度的資料單獨儲存一份,這樣就可以直接根據賣家能夠定位到資料。帶來的問題也很明顯,就是儲存變大了,兩邊資料的一致性要維護好,否則就會有問題。

總結

這篇文章主要給大家介紹了在分庫分表過程中,如何去滿足我們業務需求的多維度查詢問題。實現方案有很多,大家要根據場景選擇合適的方式。

原創:架構擺渡人(公眾號ID:jiagoubaiduren),歡迎分享,轉載請保留出處。

本文已收錄至學習網站 http://cxytiandi.com/ ,裡面有Spring Boot, Spring Cloud,分庫分表,微服務,面試等相關內容。

相關文章