Join trong batch — sort-merge, broadcast, partitioned
Ba cách join hai tập dữ liệu lớn trong batch — sort-merge, broadcast hash, partitioned hash. Chọn theo kích thước bảng và mức độ skew của join key.
TL;DR: Join trong batch quy về ba chiến lược. Sort-merge join sort cả hai bảng theo join key rồi chạy k-way merge — xử lý được bảng terabyte bất kể skew, chi phí là hai lần sort. Broadcast hash join copy bảng nhỏ vào RAM mọi executor và probe hash table — tránh shuffle bảng lớn, nhưng chỉ an toàn khi bảng nhỏ thực sự vừa RAM (Spark mặc định 10 MB, hard limit 8 GB). Partitioned hash join chia cả hai bảng theo cùng hàm hash — partition nào join độc lập, nhưng hot key skew dồn hàng triệu record về một reducer. Pitfall kinh điển: broadcast bảng "nhỏ" mà thực chất GB-scale, và hash(hot_key) dồn gấp hàng trăm tới hàng nghìn lần record so với mức trung bình về một nút.
Hệ thống đề xuất của một sàn thương mại điện tử cần join bảng events (2 TB click/view log) với bảng products (8 GB metadata: tên, giá, danh mục). Một sản phẩm hot có thể xuất hiện trong 50 triệu dòng log — trong khi sản phẩm trung bình chỉ vài trăm. Câu hỏi đặt ra: chọn chiến lược join nào? Broadcast bảng products 8 GB lên RAM của 50 executor sẽ ngốn 400 GB RAM — một tính toán có thể làm cả cluster sập. Sort-merge thì sao? Partitioned hash thì coi chừng gì?
Bài này giải thích ba chiến lược join trong batch, cơ chế bên dưới từng cái, và nguyên tắc lựa chọn theo kích thước dữ liệu và skew — vì chọn sai không chỉ chậm mà có thể làm job không bao giờ về đích.
1. Analogy — thư viện tra chéo
Thư viện có hai kệ sách: kệ A "Đơn hàng" (2 triệu cuốn) và kệ B "Sản phẩm" (500.000 cuốn). Bạn cần tra chéo: với mỗi đơn hàng, lấy thông tin sản phẩm tương ứng.
Ba cách tiếp cận khác nhau:
Sort-merge: Sắp cả hai kệ theo mã sản phẩm (một lần). Sau đó hai thủ thư đi song song từ đầu — gặp mã trùng thì ghi lại. O(n log n) lúc sort, rồi O(n+m) lúc merge.
Broadcast hash: Photo toàn bộ kệ B (nhỏ), dán một bản lên mỗi bàn làm việc. Thủ thư tra kệ A rồi tra hash table ngay tại bàn, không cần di chuyển. Nếu kệ B quá lớn thì hết chỗ đặt bản photo.
Partitioned hash: Chia cả hai kệ thành N ngăn theo ký tự đầu mã. Ngăn A1 chỉ join với ngăn B1, ngăn A2 chỉ với B2 — độc lập. Nếu mã "P001" có 90% đơn hàng (hot key), ngăn đó vẫn quá tải dù các ngăn khác rảnh.
| Thư viện | Batch join |
|---|---|
| Kệ A — Đơn hàng | Bảng events / fact (lớn) |
| Kệ B — Sản phẩm | Bảng dimension / lookup (nhỏ hơn — nhưng "nhỏ hơn" là tương đối, vẫn có thể GB-scale) |
| Sort cả hai kệ cùng mã | Sort-merge join |
| Photo kệ B để trên mọi bàn | Broadcast hash join |
| Chia ngăn theo ký tự đầu mã | Partitioned hash join |
| Mã P001 chiếm 90% đơn | Hot key skew |
Sort-merge = "dọn sạch hai kệ trước rồi hợp"; broadcast = "in kệ nhỏ ra để khắp nơi tra"; partitioned = "chia ngăn song song". Kích thước thực tế quyết định cách nào khả thi.
2. Sort-merge join — sort một lần, merge mãi mãi
Sort-merge join là chiến lược mặc định của MapReduce và Spark khi cả hai bảng lớn. Tư tưởng đơn giản: nếu cả hai bảng đã được sort theo cùng join key, việc join chỉ là chạy merge pass một lần qua cả hai.
2.1 Cơ chế
Buoc 1 — Shuffle (phat ca hai bang cung key):
map(event): emit(product_id, ("E", event)) -- phat theo join key, tag loai
map(product): emit(product_id, ("P", product)) -- ca hai bang cung key
-> shuffle gom moi record co cung product_id ve cung reducer
-> framework sort theo product_id truoc khi vao reduce
Buoc 2 — Merge (trong reducer):
reduce(product_id, [("P", product), ("E", event1), ("E", event2), ...]):
for each event in events:
emit(join(event, product)) -- product da co san cung partition
Time: O(n log n) shuffle+sort + O(n+m) merge
Space: O(1) per reducer -- streaming merge, khong load toan bo vao RAM
Hadoop gọi kỹ thuật gom cả hai bảng về cùng reducer theo join key là secondary sort: composite key (product_id, table_tag) đảm bảo bản ghi từ bảng phụ (products) luôn tới trước bản ghi sự kiện, nên reducer build lookup trong khi stream sự kiện chạy qua — không cần buffer toàn bộ.
flowchart LR EA["events<br/>p_id=42"] --> SH1["Shuffle + Sort<br/>by product_id"] PA["products<br/>p_id=42"] --> SH1 SH1 --> R1["Reducer p_id=42<br/>merge event+product"] EB["events<br/>p_id=99"] --> SH2["Shuffle + Sort<br/>by product_id"] PB["products<br/>p_id=99"] --> SH2 SH2 --> R2["Reducer p_id=99"]
2.2 Khi nào dùng
- Cả hai bảng lớn (GB–TB) — không fit broadcast.
- Dữ liệu có skew (hot key): sort-merge gom mỗi key về reducer riêng, reducer nào xử lý đúng phần của mình — không có reducer "nhận toàn đống" như hash join.
- Dữ liệu đã được sort sẵn từ bước trước → sort-merge "miễn phí" (chi phí sort gần như 0).
Chi phí chính là hai lần sort đầy đủ. Đổi lại: không cần RAM lớn tại reducer (streaming merge), và không bị phá vỡ bởi hot key skew.
Shuffle trong MapReduce (bài 02 — MapReduce) chính là bước sort này — framework sort record theo key trước reducer, nên sort-merge join là kết quả tự nhiên: bạn emit cùng join key từ cả hai bảng, framework lo phần còn lại.
Bước merge — k-way merge nhiều sorted stream — dùng cùng ý tưởng với merge sort đã học: N sorted run, merge đồng thời, O(n log k) với k là số sorted run merge cùng lúc (fan-in). Trong batch phân tán, k-way merge chạy song song trên nhiều reducer, mỗi reducer merge các run của partition mình.
3. Broadcast hash join — bơm bảng nhỏ vào RAM
Broadcast hash join tránh hoàn toàn việc shuffle bảng lớn. Thay vào đó, bảng nhỏ được copy lên RAM của mọi executor, rồi mỗi executor tự probe hash table cục bộ khi scan bảng lớn.
3.1 Cơ chế
Buoc 1 — Broadcast (driver doc bang nho):
Driver load toan bo products vao RAM
-> serialize + gui sang moi executor (broadcast variable)
-> moi executor build: HashMap<product_id, product>
Buoc 2 — Probe (map-side, khong co shuffle phase):
map(event):
product <- localHashTable.get(event.product_id) -- O(1), in RAM
if product != null:
emit(join(event, product))
Khong co reduce phase! Bang lon (events) khong di chuyen qua mang.
Time: O(m) build hash table + O(n) probe, chay song song tren moi executor
Space: hash table phai fit vao RAM cua tung executor (khong chia se)
Spark tự chọn broadcast hash join khi Spark ước lượng bảng nhỏ hơn spark.sql.autoBroadcastJoinThreshold — mặc định 10 MB. Hard limit kỹ thuật là 8 GB (trên 8 GB Spark ném exception; ngay cả dưới limit, kích thước thực tế nhân số executor là gánh nặng RAM thật sự).
3.2 Khi nào dùng
- Bảng nhỏ thực sự nhỏ — safe zone: dưới vài chục MB, không phải GB-scale.
- Muốn tránh shuffle bảng lớn: bảng lớn không di chuyển qua mạng, tiết kiệm I/O.
- Join với dimension table cố định: mã quốc gia, danh mục, trạng thái.
Pitfall chính về kích thước sẽ nói kỹ ở Section 6.
4. Partitioned hash join — chia để trị
Partitioned hash join (Spark gọi là shuffle hash join) chia cả hai bảng theo cùng một hàm hash trên join key, rồi join từng cặp partition độc lập. Ý tưởng: nếu hash(product_id) % N cho cùng kết quả trên cả hai bảng, record cùng key sẽ vào cùng partition — và mỗi partition join độc lập mà không cần toàn bộ bảng nhỏ trên RAM.
4.1 Cơ chế
Buoc 1 — Partition (shuffle ca hai bang cung ham hash):
map(event): emit(hash(product_id) % N, event)
map(product): emit(hash(product_id) % N, product)
-> cung hash value -> cung partition -> cung reducer
Buoc 2 — Build + Probe (trong tung partition):
reduce(partition_id, [events..., products...]):
localHash <- build(products trong partition nay) -- chi 1/N cua bang nho
for each event in events:
emit(join(event, localHash.get(event.product_id)))
Time: O(n+m) build + probe, song song N partition
Space: RAM = kich thuoc 1 partition cua bang nho (khong phai toan bo)
Ưu điểm so với broadcast: mỗi reducer chỉ giữ 1/N của hash table — bảng nhỏ không cần fit toàn bộ vào một nơi. Ưu điểm so với sort-merge: không cần sort, chỉ hash, thường nhanh hơn khi dữ liệu phân phối đều.
4.2 Khi nào dùng
- Cả hai bảng lớn nhưng phân phối key đều (không hot key nghiêm trọng).
- Bảng nhỏ không đủ nhỏ để broadcast, nhưng 1/N của nó vừa RAM reducer.
- Không cần sort (partitioned hash join thường nhanh hơn sort-merge khi dữ liệu đều).
Nhược điểm nặng: hot key skew dồn một partition thành khổng lồ → straggler → phá vỡ toàn bộ ưu điểm song song.
5. Khi nào chọn chiến lược nào?
Trước khi đọc bảng so sánh, thử với ba scenario:
- Bảng events 2 TB join bảng countries 200 KB (mã quốc gia — 250 quốc gia).
- Bảng orders 500 GB join bảng products 8 GB, không có sản phẩm nào chiếm quá 0,01% đơn.
- Bảng clicks 1 TB join bảng users 50 GB, user_id "influencer123" chiếm 30% clicks.
Chiến lược nào phù hợp nhất cho từng case? Vì sao? Đọc bảng rồi kiểm tra.
| Tiêu chí | Sort-merge join | Broadcast hash join | Partitioned hash join |
|---|---|---|---|
| Kích thước bảng nhỏ | Bất kỳ | ≤10 MB (Spark default); hard limit 8 GB | Bất kỳ, nhưng 1/N phải vừa RAM |
| Kích thước bảng lớn | Không giới hạn | Không giới hạn | Không giới hạn |
| Chịu hot key skew | Tốt — mỗi key về đúng reducer của nó | Tốt — probe O(1) trên local hash | Kém — hot key gom vào 1 partition khổng lồ |
| Shuffle bảng lớn | Có (shuffle + sort cả hai) | Không — bảng lớn đứng yên | Có (shuffle cả hai, không sort) |
| Chi phí sort | O(n log n) cả hai bảng | Không cần sort | Không cần sort |
| Khi nào Spark tự chọn | Fallback mặc định | Bảng nhỏ ≤ autoBroadcastJoinThreshold | Khi AQE thấy 1 side đủ nhỏ sau filter |
AQE (Adaptive Query Execution) là cơ chế Spark tối ưu lại kế hoạch join tại runtime dựa trên kích thước partition đo được thật (thay vì chỉ ước lượng tĩnh trước khi chạy). Nếu sau các bước lọc một bảng hoá ra dưới broadcast threshold → đổi sang broadcast; nếu chỉ đủ nhỏ để build hash mỗi partition (nhưng trên threshold) → đổi sang partitioned/shuffle hash.
Đáp án cho ba scenario:
- Broadcast — 200 KB vừa RAM mọi executor, không shuffle bảng events 2 TB. Đây là trường hợp lý tưởng cho broadcast.
- Partitioned hash — hai bảng lớn, phân phối đều → hash join nhanh hơn sort; không cần sort O(n log n).
- Sort-merge — user_id skew cao, sort-merge không bị straggler (mỗi reducer đúng key của mình). Hoặc partitioned hash + salting (Section 6.2).
6. Pitfall — hai bẫy hay gặp
6.1 Broadcast bảng "nhỏ" vượt RAM
❌ Nhầm: "bảng products 8 GB nhỏ hơn bảng events 2 TB — broadcast là nhanh hơn."
SAI:
products = 9 GB (bi ep BROADCAST hint)
50 executors, moi executor giu 1 ban doc lap: 50 x 9 GB = 450 GB RAM
9 GB > hard limit 8 GB -> SparkException: broadcast size exceeds limit
(ngan cach nay la ky thuat; ngay ca 1 GB tren 50 executor = 50 GB van la qua tai RAM)
✅ Đúng:
DUNG:
products 8 GB >> broadcast threshold (10 MB mac dinh)
-> dung sort-merge join hoac partitioned hash join
Broadcast chi an toan khi bang nho thuc su vua RAM moi executor
Safe zone thuc te: vai chuc MB, khong phai GB-scale
Cách tính nhanh trước khi broadcast: kích_thước_bảng × số_executor ≤ RAM khả dụng per executor. Ngưỡng 10 MB mặc định không phải con số ngẫu nhiên — đó là ước tính dè dặt để bảng broadcast không chiếm quá vài phần trăm heap executor thông thường.
6.2 Reducer skew từ hot key
❌ Nhầm: "hash(product_id) % N chia đều công việc cho N reducer."
Hash chia đều số key khác nhau, KHÔNG chia đều số record. Nếu product_id = "P001" xuất hiện trong 50 triệu dòng log (sản phẩm hot), toàn bộ 50 triệu dòng đó vào một reducer — trong khi hàng nghìn key khác mỗi cái vài trăm dòng.
Một reducer có thể nhận gấp hàng trăm tới hàng nghìn lần record so với mức trung bình (tuỳ độ nghiêng power-law của join key) — job bị straggler, toàn pipeline đứng chờ.
SAI: hash(product_id) % N — khong co xu ly hot key
"P001" -> hash -> partition 7 -> 50 trieu record (straggler)
"P002" -> hash -> partition 3 -> 200 record
"P003" -> hash -> partition 1 -> 150 record
... 998 partition khac xong trong 30 giay, partition 7 mat 45 phut ...
TODO: them salting cho hot key P001 truoc khi emit
✅ Fix: salted join
DUNG — salted join:
map(event):
salt <- random(0..N)
emit((event.product_id + "_" + salt), event) -- trai sang N partition
-- bang phu (products) phai replicate N lan de match salt:
map(product):
for salt in 0..N-1:
emit((product.id + "_" + salt), product) -- replicate
reduce((product_id + salt), [events..., product]):
-- moi partition nho, join nhanh; ket qua gop lai sau
Trade-off: bang phu tang N lan kich thuoc.
N=10, products 1 GB -> 10 GB tong cong.
Can so voi loi ich: neu straggler keo job tu 10 phut len 3 gio, xung dang.
Salting với N=10 nghĩa là bảng phụ được ghi ra 10 lần — trade-off có thể chấp nhận khi straggler nghiêm trọng, nhưng cần profiling trước: xác định hot key cụ thể (thay vì salt toàn bộ), và đo xem N bao nhiêu thì partition đủ nhỏ để loại straggler.
7. 📚 Deep Dive
- Apache Spark SQL Programming Guide — tài liệu chính thức về
autoBroadcastJoinThreshold, Adaptive Query Execution (AQE), và hintBROADCAST/MERGE/SHUFFLE_HASHđể buộc chiến lược join. - MapReduce: Simplified Data Processing on Large Clusters — Dean & Ghemawat (OSDI 2004) — §4.2 "Ordering Guarantees" (value tới reducer theo thứ tự key) là cơ sở của sort-merge join. Kỹ thuật secondary sort — composite key
(join_key, table_tag)để bản ghi bảng phụ tới trước — là của Hadoop MapReduce, không phải một section trong paper gốc. - Comparative Analysis of Skew-Join Strategies for Large-Scale Datasets with MapReduce and Spark — Phan et al. (Appl. Sci. 2022, 12(13):6554) — phân tích skew join và chiến lược salting trong hệ phân tán thực tế.
Ghi chú: Designing Data-Intensive Applications (Kleppmann) Chương 10 mục "Reduce-Side Joins and Grouping" / "Map-Side Joins" dùng đúng ba tên reduce-side join (≈ sort-merge), broadcast hash join, partitioned hash join — nguồn agnostic chuẩn, không gắn với Spark hay Hadoop cụ thể.
8. Liên hệ các bài khác
- Bài 02 — MapReduce: shuffle trong MapReduce chính là bước sort của sort-merge join — framework sort record theo key trước reducer, nên emit cùng join key từ hai bảng là đủ để join.
- Bài 04 — Dataflow và fault tolerance: trong pipeline join nhiều bước, materialization và pipelining quyết định bao nhiêu dữ liệu ghi xuống disk giữa các bước — fault tolerance khi một bước join thất bại.
- Merge sort — k-way merge: bước merge trong sort-merge join chính là k-way merge nhiều sorted stream đã học — N sorted partition, merge đồng thời, O(n log k) với k là số partition.
- External sort — sắp xếp ngoài RAM: shuffle của MapReduce thực chất là external sort phân tán — chunk-sort-merge khi dữ liệu lớn hơn RAM của từng máy.
9. Tóm tắt
- Sort-merge join: sort cả hai bảng theo join key, chạy streaming merge. Chi phí O(n log n) sort, nhưng không bị skew và xử lý được bảng terabyte; là fallback mặc định của Spark và MapReduce.
- Broadcast hash join: copy bảng nhỏ vào RAM mọi executor, probe O(1). Không shuffle bảng lớn — nhưng chỉ an toàn khi bảng nhỏ thực sự nhỏ (Spark ≤10 MB mặc định, hard limit 8 GB).
- Partitioned hash join: chia cả hai bảng cùng hàm hash, join từng partition độc lập. Tránh sort, nhanh hơn khi dữ liệu đều; hot key skew dồn một partition thành straggler.
- Bẫy broadcast: "products 8 GB nhỏ hơn events 2 TB" → broadcast 8 GB lên 50 executor là 400 GB RAM. Tính
bytes × executor counttrước. - Bẫy skew:
hash(key) % Nchia đều số key, không chia đều số record. Hot key 50 triệu dòng → 1 reducer nhận gấp hàng trăm–nghìn lần mức trung bình → straggler. - Fix skew: salted join — suffix ngẫu nhiên vào hot key, replicate bảng phụ N lần. Trade-off: bảng phụ tăng N lần kích thước.
- Nguyên tắc chọn: kích thước quyết định broadcast vs phần còn lại; skew quyết định sort-merge vs hash.
10. Tự kiểm tra
Q1Sort-merge join xử lý được hot key skew tốt hơn partitioned hash join vì lý do gì ở cấp độ cơ chế?▸
Sort-merge join gom tất cả record cùng key về một reducer theo đúng key đó — reducer xử lý toàn bộ key, bất kể số record nhiều hay ít. Hot key không tạo imbalance so với các key khác vì phân phối công việc là "mỗi reducer đúng phần của mình", không phải "chia đều số record".
Partitioned hash join dùng hash(key) % N — hash chia đều số key khác nhau, không chia đều số record. Hot key có hàng triệu record → toàn bộ vào một partition → một reducer nhận không cân xứng, trở thành straggler kéo toàn job đứng chờ.
Q2Spark có bảng products 500 MB và bảng events 3 TB. autoBroadcastJoinThreshold mặc định là 10 MB. Spark chọn chiến lược nào? Nếu bạn hint BROADCAST cho products, điều gì có thể xảy ra?▸
Mặc định Spark chọn sort-merge join vì 500 MB vượt ngưỡng broadcast 10 MB.
Nếu hint BROADCAST cho products 500 MB: Spark thử copy 500 MB lên mọi executor. Với 50 executor, tổng RAM cho bảng này là 25 GB. Nếu executor không đủ heap, job ném OutOfMemoryError hoặc bị evict — kết quả chậm hơn sort-merge ban đầu. Hard limit kỹ thuật của Spark là 8 GB per broadcast variable — 500 MB dưới limit đó, nhưng có thể vượt RAM khả dụng thực tế.
Cách đúng nếu cluster đủ RAM: nâng threshold (spark.sql.autoBroadcastJoinThreshold=600MB) và đảm bảo executor RAM đủ — Spark sẽ tự chọn broadcast. Không thì giữ sort-merge hoặc dùng partitioned hash join.
Q3Vì sao shuffle trong MapReduce chính là bước sort của sort-merge join? Mô tả liên hệ cụ thể.▸
MapReduce shuffle sort tất cả cặp key-value theo key trước khi đẩy vào reducer — đây chính xác là bước "sort cả hai bảng theo join key" của sort-merge join. Nếu cả hai bảng emit theo cùng join key (vd product_id), framework shuffle gom tất cả record cùng key về một reducer, đã sorted — reducer chỉ cần chạy streaming merge O(n+m) mà không phải sort thêm.
Nói cách khác: MapReduce đã thực hiện sort-merge join "ngầm" mỗi khi bạn emit hai bảng theo cùng join key. Đó là lý do sort-merge join là chiến lược tự nhiên nhất với MapReduce — nó tận dụng đúng cái framework đã làm sẵn.
Q4Giải thích cơ chế salted join từng bước. Tại sao cần replicate bảng phụ N lần?▸
Salted join chia đều hot key sang N partition bằng cách thêm suffix ngẫu nhiên: thay vì emit (product_id, event), emit (product_id + "_" + random(0..N), event). Kết quả: 50 triệu record của hot key "P001" trải đều sang N partition thay vì dồn vào một.
Nhưng bảng phụ (products) cũng phải match: bản gốc chỉ có key product_id="P001", không có product_id="P001_0", product_id="P001_1"... Nên phải replicate bảng phụ N lần, mỗi bản gán một suffix — để reducer nhận (P001, salt=3) vẫn tìm thấy metadata của P001 trong partition của mình.
Trade-off: bảng phụ tăng N lần kích thước. N=10 và products 1 GB → 10 GB tổng. Cần cân với lợi ích loại straggler và chỉ salt hot key đã biết (profiling trước), không salt toàn bộ.
Q5Bảng orders 500 GB join bảng users 20 GB, không có hot key. Bảng users quá lớn để broadcast. So sánh sort-merge join và partitioned hash join — cái nào nên ưu tiên và vì sao?▸
- Sort-merge join: phải sort cả hai bảng (520 GB tổng) — O(n log n). Sau sort, merge O(n+m). Ưu điểm: chịu skew tốt, framework tự handle, robust.
- Partitioned hash join: shuffle cả hai bảng, mỗi partition build hash table từ phần users tương ứng. Không sort. Với 500 partition, mỗi partition của users ~40 MB — vừa RAM dễ dàng. Chi phí O(n+m) sau shuffle.
Không có hot key → partitioned hash join thường nhanh hơn vì tránh O(n log n) sort. Sort-merge phù hợp hơn khi: (a) dữ liệu đã sorted sẵn từ bước trước (sort gần như miễn phí), hoặc (b) cần đảm bảo robustness với skew tiềm ẩn không dự đoán trước được.
Q6Tại sao nhận định 'hash(key) % N chia đều công việc cho N reducer' là sai? Cho ví dụ cụ thể với số liệu.▸
Hash chia đều số key khác nhau thành N bucket — không đảm bảo số record trong mỗi bucket bằng nhau. Record phân phối vào bucket theo key: nếu một key xuất hiện 50 triệu lần, toàn bộ 50 triệu record đó vào một bucket.
Ví dụ cụ thể: bảng clicks 1 tỷ record, N=1000 reducer. Sản phẩm "iPhone15" xuất hiện 200 triệu lần → 1 reducer nhận 200 triệu record. 999 reducer còn lại chia 800 triệu record → trung bình 800.000 mỗi cái. Reducer hot key nhận 250× nhiều hơn mức trung bình — straggler điển hình. Với phân phối power-law cực đoan (một product chiếm phần lớn traffic), tỉ lệ này còn cao hơn nhiều.
Q7Broadcast hash join không có reduce phase. Điều đó có ý nghĩa gì về I/O mạng so với sort-merge join khi join bảng events 5 TB với bảng products 5 MB?▸
Sort-merge join shuffle cả hai bảng qua mạng: 5 TB events + 5 MB products → khoảng 5 TB I/O mạng (chưa kể sort overhead).
Broadcast hash join chỉ gửi bảng nhỏ: 5 MB products broadcast sang mọi executor (vd 50 executor → 250 MB tổng). Bảng events 5 TB không di chuyển — mỗi executor chỉ đọc phần events của mình từ local/HDFS rồi probe hash table. I/O mạng giảm từ ~5 TB xuống ~250 MB.
Đây là lý do broadcast hash join nhanh hơn rõ rệt khi bảng nhỏ thực sự nhỏ: phần lớn thời gian của distributed join là chờ I/O mạng shuffle — loại bỏ shuffle bảng lớn là thắng lợi lớn nhất.
Bài tiếp theo: Dataflow engine — DAG, materialization và fault tolerance
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên