TPC-H 是事務處理性能委員會 (TPC) 制定的決策支援基準,模擬商業分析場景,包含 8 張核心表、23 條複雜 OLAP 查詢、並發資料修改,聚焦測試資料庫引擎、平台、I/O 子系統在大數據量下的查詢能力。本文提供從源碼編譯到自動化執行的完整實戰手冊。
# 1. 下載源碼 (TPC 官網需註冊) wget https://www.tpc.org/tpch/spec/tpch_2_18_0.zip unzip tpch_2_18_0.zip cd tpch_2_18_0/dbgen # 2. 複製並修改 Makefile cp makefile.suite makefile vim makefile # 關鍵變數修改: CC = gcc DATABASE = MYSQL MACHINE = LINUX WORKLOAD = TPCH # 若無 MYSQL 選項,需手動添加編譯旗標 -DMYSQL
#ifdef MYSQL #define GEN_QUERY_PLAN "" #define START_TRAN "START TRANSACTION" #define END_TRAN "COMMIT" #define SET_OUTPUT "" #define SET_ROWCOUNT "LIMIT %d;\n" #define SET_DBASE "USE %s;\n" #define STR_CMP strcasecmp #endif
make clean && make # 產出兩個核心工具: # dbgen - 數據生成器 # qgen - SQL 生成器
# 縮放因子 (Scale Factor) SF=1 約 1 GB 原始數據 # 生產基準建議 SF ≥ 100 (100 GB),測試環境可用 SF=10 (10 GB) ./dbgen -s 10 -v -f # -s 10 : Scale Factor 10 # -v : 詳細進度輸出 # -f : 強制覆蓋既有檔案 # 輸出 8 個 .tbl 檔案:customer, lineitem, nation, orders, part, partsupp, region, supplier
| 表名 | 列數 | 預估行數 (SF=10) | 核心特徵 |
|---|---|---|---|
| lineitem | 16 | 60,000,000 | 最大表,核心事實表,高基數、大量聚合 |
| orders | 9 | 15,000,000 | 訂單主表,與 lineitem 1:N |
| partsupp | 5 | 8,000,000 | 零件供應商關係 |
| part | 9 | 2,000,000 | 零件主數據 |
| customer | 8 | 1,500,000 | 客戶主數據 |
| supplier | 7 | 100,000 | 供應商主數據 |
| nation | 4 | 25 | 國家碼表 |
| region | 3 | 5 | 地區碼表 |
官方腳本針對 Informix/DB2/Oracle,需大幅修正適配 MySQL:
-- 1. 添加資料庫管理 DROP DATABASE IF EXISTS tpch; CREATE DATABASE tpch CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE tpch; -- 2. 類型映射調整 -- INTEGER → INT / BIGINT -- CHAR(n) → VARCHAR(n) 或 CHAR(n) (視固定長度) -- DATE → DATE -- DECIMAL(15,2) → DECIMAL(15,2) -- 移除非標準子句:NOT NULL DEFAULT '0' 等調整為 MySQL 語法 -- 3. 主鍵定義調整 -- PRIMARY KEY (col1, col2) 標準語法 -- 4. 分區表可選 (大表建議) -- ALTER TABLE lineitem PARTITION BY RANGE (l_shipdate) ...
-- 1. 移除 CONNECT TO TPCD; → USE tpch; -- 2. 註釋符 -- 後加空格 (MySQL 要求) -- 3. 外鍵語法標準化:引用欄位必須顯式指定 -- 原:REFERENCES TPCD.REGION; -- 新:REFERENCES TPCD.REGION(R_REGIONKEY); -- 4. 複合外鍵引用完整欄位組合 -- REFERENCES TPCD.PARTSUPP(PS_PARTKEY, PS_SUPPKEY); -- 5. 表名小寫化 (Linux 大小寫敏感) ALTER TABLE CUSTOMER RENAME TO customer; -- ... 8 張表全部小寫
# 關閉 Binlog 避免超大事務超出 max_binlog_cache_size mysql -u root -p -e "SET GLOBAL sql_log_bin=0;" # 批次導入 (按依賴順序:碼表→主表→事實表) mysql -u root -p tpch -e "LOAD DATA INFILE '/path/region.tbl' INTO TABLE region FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';" mysql -u root -p tpch -e "LOAD DATA INFILE '/path/nation.tbl' INTO TABLE nation FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';" mysql -u root -p tpch -e "LOAD DATA INFILE '/path/supplier.tbl' INTO TABLE supplier FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';" mysql -u root -p tpch -e "LOAD DATA INFILE '/path/customer.tbl' INTO TABLE customer FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';" mysql -u root -p tpch -e "LOAD DATA INFILE '/path/part.tbl' INTO TABLE part FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';" mysql -u root -p tpch -e "LOAD DATA INFILE '/path/partsupp.tbl' INTO TABLE partsupp FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';" mysql -u root -p tpch -e "LOAD DATA INFILE '/path/orders.tbl' INTO TABLE orders FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';" mysql -u root -p tpch -e "LOAD DATA INFILE '/path/lineitem.tbl' INTO TABLE lineitem FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n';" # 重啟 Binlog mysql -u root -p -e "SET GLOBAL sql_log_bin=1;"
[mysqld] bulk_insert_buffer_size = 1G innodb_buffer_pool_size = 70%_RAM innodb_log_file_size = 4G innodb_log_buffer_size = 256M innodb_flush_log_at_trx_commit = 2 innodb_doublewrite = 0 # 導入完成後恢復生產配置
# 生成 23 條查詢
mkdir queries
for i in {1..23}; do
./qgen $i | sed 's/\r//' > queries/tpch_${i}.sql
done
# 批次修正常見語法問題
cd queries
for f in *.sql; do
# 1. LIMIT 子句修正
sed -i 's/;\nLIMIT/LIMIT/g' $f
sed -i 's/LIMIT -1/LIMIT 1/g' $f
# 2. INTERVAL 後的數字移除 (MySQL 不支援 precision)
sed -i "s/interval '[0-9]*' day ([0-9]*)/interval '\1' day/g" $f
# 3. 特定查詢別名修正 (Q13, Q17 等)
# 手動檢查並修正 COUNT(*) → COUNT(*) AS c_count 等
done
#!/bin/bash
# tpch_benchmark.sh
# 用法: ./tpch_benchmark.sh [SF] [ITERATIONS] [QUERY_SUBSET]
# 例: ./tpch_benchmark.sh 10 3 "1 3 6 14 19"
SF=${1:-10}
ITER=${2:-3}
QUERIES=${3:-$(seq -f "%02g" 1 23)}
LOG="tpch_sf${SF}_$(date +%Y%m%d_%H%M%S).log"
exec > >(tee -a "$LOG") 2>&1
echo "=== TPC-H Benchmark SF=$SF Iterations=$ITER ==="
echo "Start: $(date)"
# 預熱
echo "Warming up buffer pool..."
mysql -u root -p tpch < queries/tpch_01.sql > /dev/null
for iter in $(seq 1 $ITER); do
echo "=== Iteration $iter ==="
for q in $QUERIES; do
qfile="queries/tpch_${q}.sql"
echo "[$(date)] Query $q starting..."
# 重啟 MySQL 確保冷緩衝池 (可選,視測試目的)
# systemctl restart mysql
# sleep 10
# 執行並計時
start=$(date +%s.%N)
mysql -u root -p tpch < "$qfile" > /dev/null
end=$(date +%s.%N)
runtime=$(echo "$end - $start" | bc)
echo "Query $q completed in ${runtime}s"
echo "QUERY,$SF,$iter,$q,$runtime" >> tpch_results.csv
done
done
echo "=== Benchmark Complete ==="
echo "Results saved to tpch_results.csv"
echo "End: $(date)"
| 指標 | 計算方式 | 業務含義 |
|---|---|---|
| Power@Size | 幾何平均數 (單用戶、冷啟動) | 單查詢極致效能 |
| Throughput@Size | 幾何平均數 (多用戶、併發) | 併發吞吐能力 |
| QphH@Size | √(Power × Throughput) | 綜合評分 (TPC-H 官方指標) |
| 單查詢耗時分布 | P50, P95, P99, Max | 尾部延遲、抖動分析 |
| 資源利用率 | CPU、I/O、記憶體、網路 | 瓶頸定位:CPU bound vs I/O bound |
| 問題 | 現象 | 解決 |
|---|---|---|
| qgen 生成 SQL 語法錯誤 | LIMIT -1, INTERVAL precision, 保留字衝突 | 批次 sed 修正 + 手動審查 23 條查詢 |
| 導入報 max_binlog_cache_size 錯誤 | Binlog 緩衝不足 | 關閉 sql_log_bin 或分檔導入 |
| 查詢極慢 (> 1h) | 缺索引、統計資訊缺失、參數不當 | ANALYZE TABLE、補索引、調 innodb_buffer_pool、parallel query (8.0+) |
| 磁碟空間不足 | 導入中斷、臨時表爆滿 | 預估 3-4× 原始數據空間,使用 LVM/擴容 |
| 從庫複製延遲飆升 | 主庫大事務導入 | 導入期間停止複製或用並行導入工具 |
從源碼編譯到自動化跑分,TPC-H 完整鏈路打通,讓 MySQL OLAP 能力有了可度量、可對比、可追蹤的標準尺規。