分布式 SQL 數據庫會將應用程序數據存儲在多個節點上,從存儲和計算的角度提高了可擴展性。這種分布意味著某些應用程序請求,包括 JOIN 操作和聚合,可能跨多個數據庫節點,可能導致數據在網絡中的傳輸。
為了減輕網絡延遲對整體應用程序性能的影響,一些數據庫支持共置和交錯表格。這種優化技術允許將子表格記錄與其父行一起存儲。因此,在執行查詢時,某些需要查詢父子記錄的請求可能會更快,因為數據庫節點在數據傳輸過程中的負載較小。
然而,像任何優化技術一樣,共置和交錯表格也有其優缺點。讓我們深入了解這些表格類型,以更好地理解它們的好處和權衡。
定義
共置表格(Colocated Tables)和交錯表格(Interleaved Tables)是數據庫中的優化技術,用于改善數據存儲和查詢性能。
共置表格(Colocated Tables)
共置表格是一種優化方法,允許將子表格(child table)的記錄與其父表格(parent table)的行一起存儲在相同的物理位置或相鄰的位置。它通過將相關數據放置在同一節點或相近節點上來提高查詢效率,尤其對于需要頻繁進行父子表格數據關聯的查詢來說,可以減少網絡傳輸和提升查詢性能。
交錯表格(Interleaved Tables)
交錯表格是共置表格的一種特殊類型。與共置表格不同的是,交錯表格會在同一物理表結構和數據庫文件中將子行與其父行物理地相鄰存儲,而不是分開存儲。邏輯上,這些子表格和父表格仍然是不同的表格,但物理上它們的數據行被交錯存儲,這有助于更快地執行聯合查詢和減少數據查找的次數。
總的來說,這些優化技術旨在提高數據庫查詢效率,減少數據傳輸,特別是針對需要頻繁進行父子表格數據關聯的查詢,通過優化數據存儲和組織來改善性能。
共置表格
舉個例子: 設想一個虛構公司開發電子商務應用程序,允許各種商家在線銷售商品。
該應用程序包括兩個關鍵表格,跟蹤 Customers(客戶)和他們的 Orders(訂單)(注意,顏色用于區分來自不同客戶的訂單)。
公司預計每天會有數百萬活躍客戶,并決定使用一個包含 3 個節點的分布式數據庫集群以增強可擴展性和可用性。
在開發階段,數據庫均勻地分布了所有應用程序記錄到集群中,確保每個節點存儲了可比較量的數據并處理了類似的讀寫工作負載。
在一個架構委員會會議期間,公司決定嘗試共置表格功能,該功能允許將子表格記錄與父表格的行一起存儲。
結果,Order(子表格)與 Customer(父表格)共置,并且數據庫開始在相同節點上將訂單與其客戶記錄一起存儲。
團隊選擇了實驗表共置技術來評估一些請求的性能改進,這些請求需要在 Customer 和 Order 表格之間進行 JOIN 操作。例如,當應用程序需要計算客戶的總支出時,該請求將在特定的數據庫節點上執行。
公司確實觀察到了一些查詢的性能改進。
交錯表格
在電子商務服務的開發階段,公司探索了幾個分布式 SQL 數據庫。其中一個數據庫提供了交錯表格的支持,促使團隊也嘗試了這種表格類型。
交錯表格是共置表格的一種特定類別。與共置表格類似,交錯表格將子表格記錄與其父表格記錄一起存儲。但與經典共置表格不同,經典共置表格在物理表格結構中將子和父記錄存儲在不同的物理表格結構中,交錯表格則在同一表格結構和數據庫文件中 物理地 將子行放置在其父行旁邊(邏輯上,Customer 和 Order 仍然是不同的表格)。
通過這種存儲級別的優化,公司發現了與之前經典共置表格測試的相同查詢的額外性能增加。這種增加是因為客戶及其訂單存儲在內存和磁盤中的同一頁面上,需要更少的查找。
共置和交錯表格權衡
隨著時間的推移,公司接近電子商務應用程序的預生產測試階段,出現了新的挑戰。
當團隊加載一個生產級數據集并開始負載測試時,他們遇到了共置表格的第一個權衡 — 數據和負載傾斜。此外,由于新的業務需求,工程團隊遇到了這些表格特定的另一個權衡 — 選擇最佳的父表格進行共置。
數據和負載傾斜權衡
數據傾斜是指集群中的一個節點開始存儲比其他節點顯著更多的應用程序記錄。這種不平衡通常導致負載傾斜,因為過載的節點必須處理更多的應用程序請求并處理更大的數據量。
在早期開發階段,團隊已經注意到某些客戶比其他客戶更頻繁地購物。這種客戶行為導致某些數據庫節點存儲的訂單比其他節點多。例如,第二個節點最終存儲了比第一和
第三個節點合計更多的訂單(5 > 2 + 2 = 4)。
當公司開始在使用生產級數據集的預生產環境中進行測試時,這些數據和負載傾斜問題變得更加明顯。雖然某些客戶在系統中只有幾十個訂單,但其他購物頻率更高的客戶則積累了數百甚至數千個通過應用程序處理的訂單。
這些經常購物的顧客是某些節點存儲和處理更多數據的主要原因。
據我所知,針對這種特定的數據傾斜問題沒有簡潔的解決方案。共置表格將子記錄映射到存儲父記錄的節點,并且每個父記錄一次只能映射到一個數據庫節點。
因此,為了將特定客戶的訂單分布到多個節點,必須有多個標識該客戶的記錄。例如,通過在 Customer 主鍵 (id, bucket) 中添加 bucket ID,你可以為經常購買者創建多個記錄 — Customer (1, 1), Customer (1, 2), Customer (1, 3) 等。然后,可以將客戶的訂單添加到特定的桶中,從而允許數據庫將它們分布到多個節點。然而,這種方法使應用程序邏輯變得更加復雜,需要決定桶的數量和每個新訂單的合適桶。
最佳父表格權衡
共置表格的第二個權衡與選擇最合適的父表格進行共置有關。
實際上,電子商務應用程序的數據庫架構要復雜得多,涵蓋了許多關系和依賴關系。
例如,盡管客戶最初打算購買一件商品,但通常會最終在購物車中有幾個產品。因此,一個訂單可能包括兩個或更多已購買的產品。
假設公司引入了 SoldProducts 表格來跟蹤所有客戶訂單中銷售的產品。類似于 Orders 表格,決定將這個新表格與 Customer 表格共置。
選擇這種共置策略是有原因的。應用程序經常需要執行請求,這些請求連接了 Customer、Order 和 SoldProduct 表格的數據。例如 — 客戶在最近一個月內購買了什么產品?
因此,訂單和已售產品的記錄現在都與保持其客戶記錄的數據庫節點一起存儲。
然而,在預生產測試的中途,來自業務團隊的新要求出現了。他們的目標是優先考慮一個專門用于商家和公司物流以及業務增長部門的微服務。該服務旨在使商家和公司能夠跟蹤和預測各種產品的需求和可用性。通過實施此功能,公司可以通過向具有相似喜好的客戶推薦熱門產品來提高銷售,而商家則可以主動補充產品。
工程團隊決定將表 Product(子表格)記錄與 Merchant 表格(父表格)的行共置。
然而,從性能的角度來看,這種方法證明是不夠的,因為許多查詢需要連接 Merchant、Product 和 SoldProduct 表格的數據。這樣一個查詢的示例是 — 最近 12 小時內購買的最熱門產品是什么?
從技術上講,將已售產品記錄存儲在相應的商家附近是可行的。但有一個復雜問題 — SoldProduct 記錄已經與 Customer 表格共置,以滿足另一個微服務的要求。
這是最佳父表格權衡的一個例子。例如,SoldProducts 表格一次只能與一個父表格共置。確定哪種共置策略從長遠來看是最好的通常是一項困難的任務。
總結
像每一種優化技術一樣,表共置和交錯都有其優點和權衡。要確保共置不是你的用例的過早優化,首先在沒有共置的情況下運行應用程序工作負載。檢查查詢執行計劃,并應用避免需要共置表格的優化。有時,你只需要創建適當的索引,為 JOIN 操作啟用批處理,為頁面緩沖區提供更多內存等 — 在看到執行計劃之前你永遠不會知道。但是,如果什么都不起作用,那么考慮共置表格,確保它們的權衡不會對長期產生不良影響。