在現代分散式資料庫中,水平擴展資料的需求導致了分片的廣泛採用。雖然分片有助於管理跨多個節點的大型資料集,但它也帶來了挑戰,特別是在執行連接並確保高效的資料檢索時。在本文中,我們探討了應對這些挑戰的各種概念和技術,特別關注廣播連接、分片鍵對齊和分散式查詢引擎,例如Presto 和BigQuery。此外,我們也示範如何使用 Node.js 和 Express.
在實際應用程式中處理這些問題Node.js 與 Express.js 中的分片範例
以下是如何使用 Node.js 和 Express.js 在 PostgreSQL 中實作分片。
PostgreSQL 分片範例
使用 Citus 或使用 Node.js 進行手動邏輯分片:
邏輯分片範例
分片設定表:
使用分片表(shard1 上的 user_data 和 shard2 上的 user_data)。建立 Express.js API:
基於分片鍵(例如 user_id)分發查詢。
const express = require('express'); const { Pool } = require('pg'); const poolShard1 = new Pool({ connectionString: 'postgresql://localhost/shard1' }); const poolShard2 = new Pool({ connectionString: 'postgresql://localhost/shard2' }); const app = express(); app.use(express.json()); const getShardPool = (userId) => (userId % 2 === 0 ? poolShard1 : poolShard2); app.post('/user', async (req, res) => { const { userId, data } = req.body; const pool = getShardPool(userId); try { await pool.query('INSERT INTO user_data (user_id, data) VALUES (, )', [userId, data]); res.status(200).send('User added successfully'); } catch (err) { console.error(err); res.status(500).send('Error inserting user'); } }); app.get('/user/:userId', async (req, res) => { const userId = parseInt(req.params.userId, 10); const pool = getShardPool(userId); try { const result = await pool.query('SELECT * FROM user_data WHERE user_id = ', [userId]); res.status(200).json(result.rows); } catch (err) { console.error(err); res.status(500).send('Error retrieving user'); } }); app.listen(3000, () => console.log('Server running on port 3000'));
1. 分散式資料庫中的分片
分片是跨多個資料庫執行個體或分片水平分區資料的過程,以提高效能、可擴展性和可用性。當單一資料庫執行個體無法處理大量資料或流量時,通常需要分片。
分片策略:
- 基於範圍的分片:資料根據鍵的範圍分佈在分片上,例如,按 order_date 對訂單進行分區。
- 基於雜湊的分片:透過分片鍵(例如 user_id)對資料進行雜湊處理,以將資料均勻分佈在各個分片上。
- 以目錄為基礎的分片:中央目錄追蹤資料駐留在系統中的位置。
但是,當相關表在不同鍵上分片時,或當一個表需要跨多個分片與另一個表進行聯接時,由於需要分散-聚集 操作,性能可能會下降。這就是理解廣播連接和分片鍵對齊變得至關重要的地方。
2. 分片系統中連接的挑戰
當資料駐留在不同的分片中時,在這些分片之間執行連接可能會很複雜。以下是常見挑戰的細分:
1. 分片鍵錯位:
在許多系統中,表在不同的鍵上進行分片。例如:
- users 表格可能會按 user_id 進行分片。
- 訂單表格可能會按區域分片。
執行連線時(例如,orders.user_id = users.user_id),系統需要從多個分片中取得數據,因為相關記錄可能不在同一個分片中。
2. 分散-聚集連結:
在分散-聚集連結中,系統必須:
- 向所有保存相關資料的分片發送請求。
- 跨分片的聚合結果。 這會顯著降低效能,尤其是當資料分佈在許多分片上時。
3. 廣播加入:
廣播連線 當被連接的一個表格夠小,可以廣播到所有分片時,就會發生。在這種情況下:
- 小表(例如使用者)在較大的分片表(例如訂單)所在的所有節點上複製。
- 每個節點都可以將其本地資料與廣播資料連接起來,從而避免跨分片通訊。
3. 使用分散式查詢引擎進行分片資料
分散式查詢引擎,例如 Presto 和 BigQuery 旨在跨分散式系統高效處理分片資料和聯結查詢。
急板/Trino:
Presto 是一個分散式 SQL 查詢引擎,旨在跨異質資料來源(例如關聯式資料庫、NoSQL 資料庫、資料湖)查詢大型資料集。 Presto 跨分散式資料來源執行聯接,並且可以透過最小化節點之間的資料移動來最佳化查詢。
範例用例:使用 Presto 連線分片資料
在 orders 依區域分片且 users 按 user_id 分片的場景中,Presto 可以使用其分散式執行模型跨不同分片執行連線。
查詢:
const express = require('express'); const { Pool } = require('pg'); const poolShard1 = new Pool({ connectionString: 'postgresql://localhost/shard1' }); const poolShard2 = new Pool({ connectionString: 'postgresql://localhost/shard2' }); const app = express(); app.use(express.json()); const getShardPool = (userId) => (userId % 2 === 0 ? poolShard1 : poolShard2); app.post('/user', async (req, res) => { const { userId, data } = req.body; const pool = getShardPool(userId); try { await pool.query('INSERT INTO user_data (user_id, data) VALUES (, )', [userId, data]); res.status(200).send('User added successfully'); } catch (err) { console.error(err); res.status(500).send('Error inserting user'); } }); app.get('/user/:userId', async (req, res) => { const userId = parseInt(req.params.userId, 10); const pool = getShardPool(userId); try { const result = await pool.query('SELECT * FROM user_data WHERE user_id = ', [userId]); res.status(200).json(result.rows); } catch (err) { console.error(err); res.status(500).send('Error retrieving user'); } }); app.listen(3000, () => console.log('Server running on port 3000'));
急速將:
- 使用分散-聚集取得相關使用者記錄。
- 跨節點連接資料。
Google BigQuery:
BigQuery 是一個完全託管的無伺服器資料倉儲,擅長執行大規模分析查詢。雖然 BigQuery 抽象化了分片的細節,但它會自動在多個節點之間分區和分佈資料以最佳化查詢。它可以輕鬆處理大型資料集,對於資料按時間或其他維度分區的分析查詢特別有效。
範例用例:在 BigQuery 中加入分片表
const express = require('express'); const { Pool } = require('pg'); const poolShard1 = new Pool({ connectionString: 'postgresql://localhost/shard1' }); const poolShard2 = new Pool({ connectionString: 'postgresql://localhost/shard2' }); const app = express(); app.use(express.json()); const getShardPool = (userId) => (userId % 2 === 0 ? poolShard1 : poolShard2); app.post('/user', async (req, res) => { const { userId, data } = req.body; const pool = getShardPool(userId); try { await pool.query('INSERT INTO user_data (user_id, data) VALUES (, )', [userId, data]); res.status(200).send('User added successfully'); } catch (err) { console.error(err); res.status(500).send('Error inserting user'); } }); app.get('/user/:userId', async (req, res) => { const userId = parseInt(req.params.userId, 10); const pool = getShardPool(userId); try { const result = await pool.query('SELECT * FROM user_data WHERE user_id = ', [userId]); res.status(200).json(result.rows); } catch (err) { console.error(err); res.status(500).send('Error retrieving user'); } }); app.listen(3000, () => console.log('Server running on port 3000'));
BigQuery 自動處理分區和分配,最大限度地減少手動分片的需要。
4. 處理 Node.js 應用程式中的分片鍵錯位
在 Node.js 應用程式中處理分片資料時,經常會出現 分片鍵未對齊 以及需要 分散-聚集 連接等問題。以下是如何使用 Node.js 和 Express 來應對這些挑戰。
在 Node.js 中處理廣播連線
如果連接需要在所有分片上廣播一個小表(例如用戶),您可以透過獲取一次小表並使用它與分片表中的資料連接來在應用程式層實現連接。
SELECT o.order_id, u.user_name FROM orders o JOIN users u ON o.user_id = u.user_id;
在 Node.js 中處理分散-聚集查詢
對於涉及分散-聚集連接的查詢(例如,當分片鍵未對齊時),您將需要查詢所有分片並在應用程式層聚合結果。
SELECT o.order_id, u.user_name FROM `project.dataset.orders` o JOIN `project.dataset.users` u ON o.user_id = u.user_id WHERE o.order_date BETWEEN '2024-01-01' AND '2024-12-31';
5. 分片資料查詢最佳化的最佳實務
處理分片資料和執行連線時,請考慮以下最佳實務:
對齊分片鍵:如果可能,請確保相關表使用相同的分片鍵。這最大限度地減少了跨分片連接的需求並提高了效能。
反規範化:在頻繁連接的場景中,請考慮對資料進行反規範化。例如,您可以將使用者資訊直接儲存在 posts 表中,從而減少聯結的需要。
對小表使用廣播連接:如果其中一個表足夠小,則將其廣播到所有節點以避免分散-聚集查詢。
預先連接數據:對於經常存取的數據,考慮預先連接並將結果儲存在物化視圖或快取中。
利用分散式查詢引擎:對於複雜的分析查詢,請使用Presto 或BigQuery 等自動處理分散式聯接和最佳化的系統。
6. 使用分片資料進行基於遊標的分頁的最佳實踐
在具有此類分片的分散式系統中,基於遊標的分頁需要謹慎處理,特別是因為資料分佈在多個分片中。關鍵是:
- 拆分查詢:獨立查詢每個分片以取得相關資料。
- 分頁處理:決定如何對分片資料(貼文或使用者)進行分頁,並收集相關結果。
- 在應用程式層級加入:從每個分片中取得結果,在記憶體中加入數據,然後套用下一頁的遊標邏輯。
讓我們來看看如何使用Node.js 和Express 來實現這一點,考慮到資料駐留在不同的分片上並且需要在應用程式層級進行提取後連接。
如何處理分頁和與分片表的連接
假設我們有:
- 貼文按user_id分片的表格。
- users 按 user_id 分片的表。
我們想要檢索給定用戶的分頁帖子,但由於用戶和帖子位於不同的分片上,因此我們需要拆分查詢、處理分頁,然後在應用程式層級執行聯接。
方法:
-
查詢相關分片:
- 首先,您需要跨分片查詢 posts 表以取得貼文。
- 取得相關貼文後,使用貼文中的 user_id 查詢使用者表(同樣是跨分片)。
-
分頁策略:
- 貼文分頁:您可以使用created_at、post_id或其他唯一欄位對貼文表進行分頁。
- 使用者分頁:您可能需要單獨取得使用者資料或使用 user_id 作為遊標來對使用者進行分頁。
-
應用程式層級連線:
- 從相關分片(貼文和使用者)檢索資料後,在應用程式層級加入它們。
-
處理遊標:
- 取得第一頁後,使用最後的created_at或post_id(來自貼文)作為下一個查詢的遊標。
實施範例
1. 跨分片查詢帖子
在這裡,我們將跨不同的貼文分片執行查詢,並透過遊標(例如,created_at 或 post_id)進行篩選。
2.使用Post資料跨分片查詢用戶
一旦我們從第一個查詢中獲得了相關的 post_id 和 user_id,我們將從相關分片中獲取使用者資料。
const express = require('express'); const { Pool } = require('pg'); const poolShard1 = new Pool({ connectionString: 'postgresql://localhost/shard1' }); const poolShard2 = new Pool({ connectionString: 'postgresql://localhost/shard2' }); const app = express(); app.use(express.json()); const getShardPool = (userId) => (userId % 2 === 0 ? poolShard1 : poolShard2); app.post('/user', async (req, res) => { const { userId, data } = req.body; const pool = getShardPool(userId); try { await pool.query('INSERT INTO user_data (user_id, data) VALUES (, )', [userId, data]); res.status(200).send('User added successfully'); } catch (err) { console.error(err); res.status(500).send('Error inserting user'); } }); app.get('/user/:userId', async (req, res) => { const userId = parseInt(req.params.userId, 10); const pool = getShardPool(userId); try { const result = await pool.query('SELECT * FROM user_data WHERE user_id = ', [userId]); res.status(200).json(result.rows); } catch (err) { console.error(err); res.status(500).send('Error retrieving user'); } }); app.listen(3000, () => console.log('Server running on port 3000'));
關鍵細節:
- 貼文分頁:遊標基於created_at字段或貼文中的另一個唯一字段,用於對結果進行分頁。
- 獨立查詢分片:由於貼文和使用者在不同的鍵上分片,因此我們獨立查詢每個分片,在應用程式層級執行聯接之前從所有分片收集資料。
- 遊標處理:檢索結果後,我們使用貼文中的last created_at(或post_id)來產生下一頁的遊標。
- 在應用程式層級加入:從相關分片取得資料後,我們根據記憶體中的 user_id 將貼文與使用者資料加入。
結論
管理分散式系統中的分片資料提出了獨特的挑戰,特別是在執行高效連接時。了解廣播連接、分散-聚集連接等技術並利用分散式查詢引擎可以顯著提高查詢效能。此外,在應用程式層級查詢中,必須考慮分片鍵對齊、非規範化和最佳化的查詢策略。透過遵循這些最佳實踐並利用正確的工具,開發人員可以確保他們的應用程式有效處理分片資料並大規模維持效能。
以上是處理分散式系統中的分割資料:深入探討連線、廣播和查詢最佳化的詳細內容。更多資訊請關注PHP中文網其他相關文章!

選擇Python還是JavaScript取決於項目類型:1)數據科學和自動化任務選擇Python;2)前端和全棧開發選擇JavaScript。 Python因其在數據處理和自動化方面的強大庫而備受青睞,而JavaScript則因其在網頁交互和全棧開發中的優勢而不可或缺。

Python和JavaScript各有優勢,選擇取決於項目需求和個人偏好。 1.Python易學,語法簡潔,適用於數據科學和後端開發,但執行速度較慢。 2.JavaScript在前端開發中無處不在,異步編程能力強,Node.js使其適用於全棧開發,但語法可能複雜且易出錯。

javascriptisnotbuiltoncorc; sanInterpretedlanguagethatrunsonenginesoftenwritteninc.1)JavascriptwasdesignedAsignedAsalightWeight,drackendedlanguageforwebbrowsers.2)Enginesevolvedfromsimpleterterpretpretpretpretpreterterpretpretpretpretpretpretpretpretpretcompilerers,典型地,替代品。

JavaScript可用於前端和後端開發。前端通過DOM操作增強用戶體驗,後端通過Node.js處理服務器任務。 1.前端示例:改變網頁文本內容。 2.後端示例:創建Node.js服務器。

選擇Python還是JavaScript應基於職業發展、學習曲線和生態系統:1)職業發展:Python適合數據科學和後端開發,JavaScript適合前端和全棧開發。 2)學習曲線:Python語法簡潔,適合初學者;JavaScript語法靈活。 3)生態系統:Python有豐富的科學計算庫,JavaScript有強大的前端框架。

JavaScript框架的強大之處在於簡化開發、提升用戶體驗和應用性能。選擇框架時應考慮:1.項目規模和復雜度,2.團隊經驗,3.生態系統和社區支持。

引言我知道你可能會覺得奇怪,JavaScript、C 和瀏覽器之間到底有什麼關係?它們之間看似毫無關聯,但實際上,它們在現代網絡開發中扮演著非常重要的角色。今天我們就來深入探討一下這三者之間的緊密聯繫。通過這篇文章,你將了解到JavaScript如何在瀏覽器中運行,C 在瀏覽器引擎中的作用,以及它們如何共同推動網頁的渲染和交互。 JavaScript與瀏覽器的關係我們都知道,JavaScript是前端開發的核心語言,它直接在瀏覽器中運行,讓網頁變得生動有趣。你是否曾經想過,為什麼JavaScr

Node.js擅長於高效I/O,這在很大程度上要歸功於流。 流媒體匯總處理數據,避免內存過載 - 大型文件,網絡任務和實時應用程序的理想。將流與打字稿的類型安全結合起來創建POWE


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

SublimeText3漢化版
中文版,非常好用

SublimeText3 Linux新版
SublimeText3 Linux最新版

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器