今天原本想說來做個實驗,但需要先來介紹個 DataFusion
因為明天要來測量 SortExec,那今天先把工具介紹一下
提到 Database system 就必須簡單說明一下會用到的語言,也就是鼎鼎大名的SQL
SQL(Structured Query Language)他是用來描述需要哪些資料
只說要哪些欄、做什麼事;迴圈怎麼掃、排序用哪種演算法,交給引擎
這就是 declarative 宣告式
例如:
SELECT id, g FROM t WHERE g > 50 ORDER BY g;
沒指定用哪種排序、一批幾列,根本不需要管那些,因為那些是 DataFusion 要處理的事。
若改成寫 for 迴圈掃檔、比較、再排,那就是 imperative 命令式——步驟你全包辦。
DataFusion 是用 Rust 寫的查詢引擎:把那句 SQL 讀懂、規劃出執行步驟、然後拿去算。
而 datafusion-cli,只是換一個入口:同一個函式庫,外面加了讀檔、畫表格、等到看到分號才送出。
底下跑的還是 Arrow 的 RecordBatch,跟前幾天講的一批一批是同一件事。

引擎不是拿到字串就開始掃資料
中間還有兩層計劃:邏輯計劃說「做什麼」,實體計劃才說「用哪個算式做」。
後面 EXPLAIN 印出來的那棵樹,就是右邊那格實體計劃,最頂的 SortExec 先記著,明天的實驗就在那。
brew install datafusion
cargo install datafusion-cli
docker run -it --rm apache/datafusion-cli
裝好打 datafusion-cli 進到互動介面,看到 > 提示字元就對了
$ datafusion-cli
DataFusion CLI v54.1.0
>
進到互動介面後,指令分兩個塊:
; 結尾才會送出,少打分號 CLI 會一路等下一行,直到看到 ; 為止(Oracle SQL*Plus 用 / 觸發跑緩衝區,這裡沒這東西,/ 只會被當成下一句的開頭卡在那)常用的幾個:
| 指令 | 做什麼 |
|---|---|
\? |
列出全部 meta command |
\d |
列出目前有哪些表 |
\d 表名 |
看某張表的欄位 |
\q |
離開(或按 Ctrl+D) |
想改引擎行為,用 SET:
SET datafusion.execution.batch_size = 4096;
SHOW ALL; -- 看目前全部 config
SHOW datafusion.execution.batch_size; -- 只看某一項
SET / SHOW 也算 SQL,結尾一樣要 ;
一次餵一個檔案的 SQL,啟動時加 -f:
datafusion-cli -f script.sql
SQL 子句的書寫順序是固定的,寫錯 parser 直接擋下,不會幫你調:
WITH … SELECT … FROM … JOIN … WHERE … GROUP BY … HAVING … ORDER BY … LIMIT … OFFSET
但執行順序不一樣,大致是 FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT。SELECT 排在 WHERE 之後,所以 SELECT 裡取的別名在 WHERE 用不到,在 ORDER BY 卻可以。
先弄一筆假資料玩玩,直接用 VALUES 造一張表:
CREATE TABLE demo AS
SELECT * FROM (VALUES
(1, 'a', 10.0),
(2, 'b', 20.0),
(3, 'c', 30.0),
(4, 'd', 40.0)
) AS t(id, name, price);
跑個 SELECT 確認資料在了:
SELECT * FROM demo WHERE price > 15;
會輸出
> SELECT * FROM demo WHERE price > 15;
+----+------+-------+
| id | name | price |
+----+------+-------+
| 2 | b | 20.0 |
| 3 | c | 30.0 |
| 4 | d | 40.0 |
+----+------+-------+
3 row(s) fetched.
Elapsed 0.013 seconds.
也可以直接讀本地檔案,Parquet、CSV、JSON 都吃:
SELECT * FROM 'data.parquet' LIMIT 5;
想看引擎怎麼規劃這句 SQL,加 EXPLAIN,印出來的就是上面那張圖裡的實體計劃:
EXPLAIN SELECT * FROM demo ORDER BY price DESC;
會吐出一棵 plan tree,長得像這樣:
> EXPLAIN SELECT * FROM demo ORDER BY price DESC;
+---------------+-------------------------------+
| plan_type | plan |
+---------------+-------------------------------+
| physical_plan | ┌───────────────────────────┐ |
| | │ SortExec │ |
| | │ -------------------- │ |
| | │ price@2 DESC │ |
| | └─────────────┬─────────────┘ |
| | ┌─────────────┴─────────────┐ |
| | │ DataSourceExec │ |
| | │ -------------------- │ |
| | │ bytes: 1432 │ |
| | │ format: memory │ |
| | │ rows: 1 │ |
| | └───────────────────────────┘ |
| | |
+---------------+-------------------------------+
1 row(s) fetched.
Elapsed 0.004 seconds.
最頂那個 SortExec 就是明天要做的實驗,多欄排序為什麼比單欄貴這麼多,答案就在這裡
那就明天見~