🌐 This page hasn't been translated yet — showing the original Chinese. Translated posts

#sql

Coordinator 收 query、規劃、分派 Segment 1 Segment 2 Segment 3 DISTRIBUTED BY (分佈鍵):用 hash(分佈鍵) 決定每列落哪個 segment,查詢在每台平行跑 ⚠ 分佈鍵不均勻 → 某 segment 資料爆多(skew),平行失效、最慢那台拖垮全部

當 SQL 跑在 MPP 上:Greenplum 與 Cloudberry

· tech · 約 5 分鐘 · 📚 SQL 我以為我懂 #12

整個 SQL 系列的壓軸。前面 11 篇都跑在單機 PostgreSQL,這篇把同一批 SQL 放到 MPP(Massively Parallel Processing,大規模平行處理) 上——Gre…

#sql#data-engineering

① Dirty Read 髒讀 T1 T2 餘額改 200(未提交) 讀到餘額 200 ❌ ROLLBACK ② Non-repeatable Read 不可重複讀 T1 T2 讀餘額 100 餘額改 200 並提交 又讀餘額 200 ❌ ③ Phantom Read 幻讀 T1 T2 查到 3 筆訂單 插入 1 筆符合訂單並提交 又查到 4 筆 ❌ 時間 →

交易與隔離層級:併發不打架的分級

· tech · 約 6 分鐘 · 📚 SQL 我以為我懂 #11

前面講的都是「一個查詢怎麼跑得快」(索引、EXPLAIN),這篇換個維度:很多交易同時跑,怎麼不互相打架? 這就是交易與隔離層級。(這裡講單機 PostgreSQL 的實務;分散式交易與一致性,交給姊…

#sql#concept

Nested Loop 內表(有索引更快) 外表每列 → 查內表一次 適合:小表 / 內表有索引 Hash Join 小表 Hash 表(記憶體) 大表 小表建 hash,大表 probe 適合:大表、等值 join Merge Join 1 3 5 2 4 6 兩側排序後,像拉鍊合併 適合:已排序 / 有索引

讀懂 EXPLAIN:優化器到底怎麼跑你的 query

· tech · 約 3 分鐘 · 📚 SQL 我以為我懂 #10

上一篇留了一個問題:索引到底有沒有被用到?答案就在 EXPLAIN 裡。這篇是我之前寫的 Spark 執行計畫那篇的 SQL 版姊妹作——同一套「讀計畫、找瓶頸」的思維,換一個引擎。學會讀 EXPLA…

#sql#performance

沒索引:Seq Scan(全表掃) 列 1 列 2 列 3 列 4 列 5 ← 目標 列 6 逐列掃過才找到 → O(n),資料越多越慢 有索引:B-tree 節點 節點 目標 沿樹往下幾步就到 → O(log n)

索引為什麼快 —— 也為什麼會失效

· tech · 約 2 分鐘 · 📚 SQL 我以為我懂 #9

接下來換個主題:引擎與效能。第一個要懂的就是索引——為什麼加了它查詢快幾百倍,又為什麼有時加了卻好像沒用。這兩個問題的答案,都藏在它的資料結構裡:B-tree。 沒有索引時,WHERE id = 50…

#sql#performance

直接 GROUP BY date_trunc 日期筆數 7/013 7/025 7/03 沒這列 ✗ 7/042 補洞 generate_series + COALESCE 0 7/013 7/025 7/030 7/042 GROUP BY 只產出「有資料」的桶 —— 沒訂單的 7/03 整列消失,時間序列就斷了

時間分桶與 SCD:SQL 處理時間的兩個坑

· tech · 約 3 分鐘 · 📚 SQL 我以為我懂 #8

接著上一篇的「區間」,這篇講時間在 SQL 裡的兩個坑——它們都源自同一件事:時間是連續的,但你的資料是離散的事件。 中間必然有「什麼都沒發生」的空隙,以及「值變了但你沒記」的變化。SQL 不會自動幫…

#sql#data-engineering

① 完全相同的列 (1, A, 100) (1, A, 100) (1, A, 100) DISTINCT (1, A, 100) 整列一模一樣 → 去掉多的 DISTINCT / GROUP BY 就能解 ② 同一 key、多筆版本 user1 · 待付 · 2/01 user1 · 已付 · 2/03 user1 · 退款 · 2/05 ROW_NUMBER 留最新 user1 · 退款 · 2/05 列不相同 → DISTINCT 沒用 要挑「代表」那一筆

去重的正確姿勢:DISTINCT 不是唯一解

· tech · 約 4 分鐘 · 📚 SQL 我以為我懂 #6

資料重複幾乎是資料工程的日常:pipeline 重跑重複匯入、CDC 把同一筆的多個版本都撈進來、JOIN 的 fan-out 把列複製。很多人一講到去重就 DISTINCT——但去重根本不只 DIS…

#sql#data-engineering

輸入(orders):4 列 A · 100 A · 250 B · 80 B · 120 GROUP BY(收合) A · SUM 350 B · SUM 200 4 列 → 2 列(每組收成一列) SUM() OVER(不收合) A · 100組計 350 A · 250組計 350 B · 80組計 200 B · 120組計 200 4 列 → 4 列(每列多一欄看整組的值)

Window Function:不收合的聚合

· tech · 約 4 分鐘 · 📚 SQL 我以為我懂 #5

上一篇的 GROUP BY 把每組收合成一列。但你一定遇過這種需求:「我想要整組的計算,又想保留每一列。」 例如——在每一筆訂單旁邊,標上它佔該客戶總額的比例;或在每個月的營收旁,標上跟上個月的差。收…

#sql#concept#window-function

原始列(orders) A · amount 100 A · amount 250 B · amount 80 B · amount 120 B · amount 50 GROUP BY customer 收合後:每組一列 customer = ACOUNT=2 · SUM=350 customer = BCOUNT=3 · SUM=250 amount 一組有多個值(100/250)→ 不能裸選,要用聚合(SUM/AVG…)壓成一個數

GROUP BY:把多列收合成一列

· tech · 約 5 分鐘 · 📚 SQL 我以為我懂 #4

GROUP BY 每個人都會寫,但幾乎每個人也都被那句 column "..." must appear in the GROUP BY clause 擋過,而且常常搞不懂「我就選個欄位,為什麼不行?…

#sql#concept

SQL 的邏輯有三個值(不是兩個) TRUE 條件成立 FALSE 條件不成立 UNKNOWN 不知道 ↑ 任何跟 NULL 的比較都落這裡 age = NULL、age <> NULL 都是 WHERE / ON / HAVING 只放行 TRUE TRUE → ✓ 保留 FALSE → ✗ 丟 UNKNOWN → ✗ 丟

NULL 不是值,是「不知道」

· tech · 約 6 分鐘 · 📚 SQL 我以為我懂 #3

上一篇的 LEFT JOIN,會幫沒配到的列補上 NULL。那個 NULL 就是這篇的主角——它是無數 SQL bug 的源頭,而根本原因只有一句:NULL 不是一個值,是「不知道」。 一旦你把它讀成…

#sql#concept

右表 R:訂單(user 欄) A A B 左表 L:使用者 使用者 A 使用者 B 使用者 C A 配到 2 筆 → 結果 A 出現兩次 B 配到 1 筆 C 配不到 → INNER 丟掉 LEFT 補 (C, NULL) ON 符合(留下) 不符合(丟棄)

JOIN 的真相:先算笛卡爾積,再過濾

· tech · 約 6 分鐘 · 📚 SQL 我以為我懂 #2

上一篇把「你寫的順序不是它跑的順序」講清楚了。這篇用同一把鑰匙拆穿 JOIN。很多人把 JOIN 想成「把兩張表黏在一起」,然後死背 INNER/LEFT/RIGHT/FULL 各自的行為。但其實它們…

#sql#concept

你這樣寫 DB 這樣跑(邏輯順序) SELECT FROM / JOIN WHERE GROUP BY HAVING ORDER BY LIMIT ① FROM / JOIN ② WHERE ③ GROUP BY ④ HAVING ⑤ SELECT ⑥ ORDER BY ⑦ LIMIT

你寫的 SQL 不是照你寫的順序跑

· tech · 約 4 分鐘 · 📚 SQL 我以為我懂 #1

你寫 SQL,幾乎都是 SELECT 開頭。寫久了很自然會以為:它就是從 SELECT 開始跑的。但不是——SQL 是宣告式的,你寫的是「要什麼」,引擎自己決定「怎麼跑、照什麼順序跑」,而它跑的順序跟…

#sql#concept