Doris 查詢太慢?要不要試試這幾項加速技術
Apache Doris 作為一款現代化的 MPP 分析型數據庫,其查詢性能一直是核心優勢。本文將深入探討 Doris 的查詢加速技術體系,從執行引擎優化到緩存機制,從 Join 策略到資源管理,結合具體場景和代碼示例,全面解析如何最大化 Doris 的查詢性能。

一、執行引擎:Pipeline 與 PipelineX
1. 傳統執行引擎的瓶頸
傳統火山模型(Volcano Model)中,每個操作符(Operator)通過 Next() 方法逐條拉取數據,導致 CPU 緩存利用率低、函數調用開銷大:
// 傳統火山模型偽代碼
while (row = child_op->Next()) {
processed_row = process(row);
emit(processed_row);
}2. Pipeline 執行引擎原理
Pipeline 引擎通過向量化執行和批處理技術優化:
-- 啟用 Pipeline 引擎
set enable_pipeline_engine = true;
-- 查看執行計劃是否使用 Pipeline
EXPLAIN SELECT ... FROM ...;核心優勢:
- 批處理:一次處理 1024 行數據(默認批大?。?/li>
- 向量化:利用 SIMD 指令加速計算
- 流水線并行:多線程并行執行不同階段
3. PipelineX 引擎增強
PipelineX 在 Pipeline 基礎上增加了本地shuffle優化:
-- 啟用 PipelineX
set enable_pipeline_x_engine = true;
-- 查看執行計劃中的 LocalExchange 算子
EXPLAIN SELECT COUNT(*) FROM large_table GROUP BY region;適用場景:
- 大數據量聚合查詢
- 需要本地預聚合的復雜查詢
二、查詢緩存:SQL Cache
1. 緩存機制原理
SQL Cache 基于查詢文本和參數精確匹配:
-- 啟用 SQL Cache
SET enable_sql_cache = true;
-- 查看緩存命中率
SHOW VARIABLES LIKE '%sql_cache%';緩存命中條件:
- 查詢文本完全一致(包括空格和大小寫)
- 參數值相同
- 涉及表數據未變更
2. 緩存優化實踐
-- 1. 使用參數化查詢提高緩存命中率
-- 低效方式(每次參數不同都生成新緩存項)
SELECT*FROM orders WHERE user_id =1001;
SELECT*FROM orders WHERE user_id =1002;
-- 高效方式(使用視圖或CTE)
CREATEVIEW user_orders AS
SELECT*FROM orders WHERE user_id = ${user_id};
-- 2. 控制緩存粒度
-- 小結果集查詢適合緩存
SELECTCOUNT(*) FROM orders WHEREdate='2023-10-01';
-- 大結果集查詢禁用緩存
SET enable_sql_cache =false;
SELECT*FROM large_table;三、Join 優化策略
1. Bucket Shuffle Join
通過數據分布預定位減少網絡傳輸:
-- 創建表時指定分布鍵
CREATE TABLE orders (
order_id BIGINT,
user_id BIGINT,
...
) DISTRIBUTED BY HASH(user_id) BUCKETS 32;
CREATE TABLE users (
user_id BIGINT,
...
) DISTRIBUTED BY HASH(user_id) BUCKETS 32;
-- 查詢自動使用 Bucket Shuffle Join
EXPLAIN
SELECT o.*, u.name
FROM orders o
JOIN users u ON o.user_id = u.user_id;優化效果:
- 減少 90%+ 的網絡數據傳輸
- 適用于大表 Join 大表場景
2. Colocation Join
共址 Join 保證關聯數據在同一節點:
-- 創建同組(Group)的表
CREATE TABLE table_a (
k1 INT,
...
) DISTRIBUTED BY HASH(k1) BUCKETS 32
PROPERTIES (
"colocation_with" = "group1"
);
CREATE TABLE table_b (
k1 INT,
...
) DISTRIBUTED BY HASH(k1) BUCKETS 32
PROPERTIES (
"colocation_with" = "group1"
);
-- 查詢自動使用 Colocation Join
EXPLAIN
SELECT a.*, b.*
FROM table_a a
JOIN table_b b ON a.k1 = b.k1;適用場景:
- 頻繁 Join 的維度表
- 數據量相對穩定的表
3. Runtime Filter
動態過濾減少 Join 數據量:
-- 啟用 Runtime Filter
SET enable_runtime_filter = true;
-- 查看執行計劃中的 Runtime Filter
EXPLAIN
SELECT o.*
FROM orders o
JOIN (SELECT user_id FROM vip_users) v
ON o.user_id = v.user_id;優化類型:
- IN Filter:適用于高基數字段
- Bloom Filter:適用于超高基數字段
- MinMax Filter:適用于數值類型
-- 手動調整 Runtime Filter 類型
SET runtime_filter_type = "BLOOM_FILTER";四、高效去重技術
1. BITMAP 精準去重
-- 創建表時使用 BITMAP 類型
CREATE TABLE user_actions (
user_id BIGINT,
action_date DATE,
actions BITMAP BITMAP_UNION
) AGGREGATE KEY(user_id, action_date);
-- 數據導入
INSERT INTO user_actions VALUES
(1001, '2023-10-01', to_bitmap(101)),
(1001, '2023-10-01', to_bitmap(102)),
(1001, '2023-10-01', to_bitmap(101));
-- 查詢去重結果
SELECT
user_id,
action_date,
bitmap_union_count(actions) AS unique_actions
FROM user_actions
GROUPBY user_id, action_date;性能對比:
-- 傳統 COUNT(DISTINCT) 方式
SELECT user_id, COUNT(DISTINCT action_id)
FROM user_actions_raw
GROUP BY user_id;
-- BITMAP 方式(快 5-10 倍)
SELECT user_id, bitmap_union_count(actions)
FROM user_actions
GROUP BY user_id;2. HLL 近似去重
-- 創建表時使用 HLL 類型
CREATE TABLE page_views (
page_id INT,
view_date DATE,
users HLL HLL_UNION
) AGGREGATE KEY(page_id, view_date);
-- 數據導入
INSERT INTO page_views VALUES
(1001, '2023-10-01', hll_hash(1001)),
(1001, '2023-10-01', hll_hash(1002)),
(1001, '2023-10-01', hll_hash(1001));
-- 查詢近似去重結果
SELECT
page_id,
view_date,
hll_union_agg(users) AS approx_unique_users
FROM page_views
GROUPBY page_id, view_date;誤差控制:
-- 設置 HLL 精度(默認 12,精度越高誤差越?。?SET hll_precision = 16;五、高并發點查優化
1. 行存與列存結合
-- 創建 Unique 模型表(自動行存)
CREATE TABLE orders (
order_id BIGINT,
user_id BIGINT,
amount DECIMAL(10,2),
status VARCHAR(20)
) UNIQUE KEY(order_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 32;
-- 查詢自動使用行存優化
SELECT * FROM orders WHERE order_id = 1000001;2. PreparedStatement 優化
// Java 代碼示例
String sql = "SELECT * FROM orders WHERE order_id = ?";
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setInt(1, 1000001);
ResultSet rs = stmt.executeQuery();
// 處理結果
}優化效果:
- 減少 SQL 解析開銷
- 提高執行計劃復用率
3. 行緩存配置
-- 啟用行緩存
SET enable_row_cache = true;
-- 調整行緩存大小(默認 2MB)
SET row_cache_mem_limit = "50MB";
-- 查看緩存命中率
SHOW BACKENDS;
-- 然后訪問 BE 的 metrics 頁面查看 row_cache_hit_rate六、TOPN 查詢優化
1. 優化原理
TOPN 查詢通過提前終止和堆排序優化:
-- 傳統方式(全排序后取前N)
SELECT * FROM orders ORDER BY amount DESC LIMIT 10;
-- 優化方式(使用 TopN 算子)
EXPLAIN
SELECT * FROM orders ORDER BY amount DESC LIMIT 10;2. 配置優化
-- 啟用 TopN 優化
SET enable_topn_opt = true;
-- 調整 TopN 緩存大小
SET topn_cache_size = 1024;七、查詢分析與調優
1. 獲取執行 Profile
-- 執行查詢并獲取 Profile
SET show_profile = true;
SELECT COUNT(*) FROM large_table GROUP BY region;
-- 查看詳細 Profile
SHOW PROFILE;關鍵指標分析:
- ScanNode:數據掃描時間
- HashJoinNode:Join 階段耗時
- AggregationNode:聚合計算時間
- ExchangeNode:數據傳輸時間
2. 查詢分析示例
-- 示例:分析慢查詢
-- 1. 獲取查詢ID
SHOW PROCESSLIST;
-- 2. 獲取指定查詢的 Profile
SHOW PROFILE FOR QUERY 'query_id';
-- 3. 分析 Profile 中的瓶頸
-- 例如發現 ScanNode 耗時過長:
ScanNode:
- RowsRead: 100000000
- BytesRead: 2GB
- TotalTime: 5.2s
- IOTime: 4.8s # IO 瓶頸
-- 優化方案:增加緩存或優化存儲八、資源管理與隔離
1. Workload Group 資源隔離
-- 創建資源組
CREATE WORKLOAD GROUP "analytics"
PROPERTIES (
"cpu_limit" = "50%",
"memory_limit" = "30%",
"concurrency_limit" = "10"
);
-- 創建資源組
CREATE WORKLOAD GROUP "etl"
PROPERTIES (
"cpu_limit" = "30%",
"memory_limit" = "50%",
"concurrency_limit" = "5"
);
-- 將用戶綁定到資源組
CREATEUSER'analyst'@'%' IDENTIFIED BY'password'
PROPERTIES ("workload_group" = "analytics");
CREATEUSER'etl_user'@'%' IDENTIFIED BY'password'
PROPERTIES ("workload_group" = "etl");2. 查詢優先級管理
-- 設置查詢優先級
SET QUERY_PRIORITY = 'HIGH';
-- 在資源組中配置優先級
ALTER WORKLOAD GROUP "analytics"
SET PROPERTIES ("query_priority" = "HIGH");九、綜合優化案例
1. 電商訂單分析場景
-- 1. 表設計優化
CREATE TABLE orders (
order_id BIGINT,
user_id BIGINT,
order_date DATE,
amount DECIMAL(10,2),
status VARCHAR(20),
region VARCHAR(20),
INDEX idx_user (user_id) USING BITMAP,
INDEX idx_date (order_date)
) DUPLICATE KEY(order_id)
PARTITIONBYRANGE(order_date) (
PARTITION p202301 VALUES LESS THAN ('2023-02-01'),
PARTITION p202302 VALUES LESS THAN ('2023-03-01')
)
DISTRIBUTED BY HASH(order_id) BUCKETS 32;
-- 2. 查詢優化示例
-- 查詢:各區域月度訂單統計
SELECT
region,
DATE_TRUNC('month', order_date) ASmonth,
COUNT(DISTINCT order_id) AS order_count,
SUM(amount) AS total_amount
FROM orders
WHERE order_date BETWEEN'2023-01-01'AND'2023-12-31'
GROUPBY region, DATE_TRUNC('month', order_date)
ORDERBY region, month;
-- 優化措施:
-- a. 分區裁剪(自動)
-- b. 使用 BITMAP 索引加速 COUNT(DISTINCT)
-- c. 聚合下推(自動)2. 實時監控儀表盤場景
-- 1. 創建物化視圖
CREATE MATERIALIZED VIEW mv_user_stats
REFRESH ASYNC EVERY'1 HOUR'
ASSELECT
user_id,
COUNT(*) AS order_count,
SUM(amount) AS total_amount,
MAX(order_date) AS last_order_date
FROM orders
GROUPBY user_id;
-- 2. 查詢物化視圖
SELECT*FROM mv_user_stats
WHERE user_id =1001;
-- 3. 監控物化視圖狀態
SHOW MATERIALIZED VIEWS;十、優秀實踐總結
(1) 執行引擎選擇:
- 通用查詢啟用 enable_pipeline_engine = true
- 復雜聚合查詢啟用 enable_pipeline_x_engine = true
(2) Join 優化策略:
- 優先使用 Bucket Shuffle Join
- 頻繁 Join 的表使用 Colocation Join
- 大表 Join 小表使用 Runtime Filter
(3) 去重技術選擇:
- 精準去重使用 BITMAP
- 大數據集近似去重使用 HLL
(4) 點查優化組合:
- Unique 模型 + PreparedStatement + 行緩存
(5) 資源管理:
- 關鍵業務使用高優先級 Workload Group
- 監控內存使用,避免 OOM
(6) 查詢分析:
- 定期分析慢查詢 Profile
- 關注 IO、CPU 和內存瓶頸
通過綜合運用這些優化技術,Apache Doris 可以在大多數分析場景下實現亞秒級響應,滿足高并發、低延遲的查詢需求。實際應用中,建議結合業務特點和數據特征,選擇最適合的優化組合方案。





















