全部產品
Search
文件中心

Hologres:Dynamic Table查詢改寫

更新時間:Feb 07, 2026

本文介紹 Hologres Dynamic Table 的查詢改寫能力、使用方式與限制。

查詢改寫介紹

在巨量資料/數倉情境中,明細表資料量通常很大(億級、百億級),而業務與分析查詢又高度依賴在明細表上進行多維 GROUP BY + 彙總,例如:按天 / 小時 / 城市統計訂單量、GMV;按渠道 / 終端統計 PV/UV、轉化率等。如果每次都直接在明細表上做彙總,會遇到如下問題:

  • 彙總成本高:每次查詢都從明細表全表或大範圍掃描並彙總,消耗大量 CPU 和 IO;

  • 明細表壓力大:影響同庫內其他任務,或需要頻繁擴容。

Hologres 提供 Dynamic Table + 查詢改寫能力:當某張基表上已經通過 Dynamic Table 做了預彙總,最佳化器可以在滿足條件時,將使用者寫的“面向基表的彙總查詢”自動改寫為“對Dynamic Table 的查詢”,從而跳過昂貴的彙總計算。主要收益有:

  • 減輕明細表彙總壓力:高頻指標(訂單數、GMV、PV/UV 等)可從 Dynamic Table 直接讀取彙總結果,減少對明細表的重複掃描和彙總。

  • 顯著提升查詢響應速度:報表、自助分析、互動式查詢在命中 Dynamic Table 時,彙總計算大幅減少,延遲降低,使用體驗接近“查寬表”。

  • 對上層使用無侵入:資料分析師、業務開發依然只需瞭解基表模型;Dynamic Table 的設計與維護由數倉/平台團隊統一負責;效能最佳化對上層透明。

通過Hologres Dynamic Table查詢改寫,可以很好的支援如下情境:

  • 即時/准即時營運看板和監控;

  • 多維度 BI 分析、自助取數;

  • 核心指標體系(GMV、訂單量、活躍使用者數等)的統一口徑加速。

使用與限制

  • 版本限制:僅Hologres 4.1及以上版本支援該功能

  • 查詢一致性限制:查詢改寫基於 Dynamic Table 最近一次重新整理結果,與基表最新狀態相比,存在一定時間視窗的延遲,屬於弱一致行為。

  • 基表類型限制:

    • 支援的基表類型有:Hologres內表、Paimon外表(Foreign Table方式建立)、MaxCompute外表(Foreign Table方式建立)

    • 如果基表是Hologres分區表,不支援基表為物理分區表。但基表可以是邏輯分區

    • 不支援External Table

  • Dynamic Table表類型限制:

    • 支援:非分區 Dynamic Table;邏輯分區的 Dynamic Table;

    • 不支援:物理分區的 Dynamic Table;External Dynamic Table。

  • Dynamic Table中Query 定義限制:

    • Query中僅支援單表,暫不支援多表

    • Query中不支援FILTER 子句的彙總(如 sum(x) FILTER (WHERE ...)

    • Query中不支援在 SELECT 中引入基於彙總結果的額外計算資料行(如 sum(x)/count(x)

開啟與配置查詢改寫

使用建議:適合看板、監控、分析等可接受秒級~分鐘級延遲的情境;強即時、嚴對賬情境建議直接查基表或採用其他強一致方案。

開啟查詢改寫

當發起對基表的查詢時,需要在查詢時,加上hg_enable_query_rewriteGUC參數,來控制該查詢是否命中查詢改寫:

說明

不建議在 DB 層級開啟,可能帶來效能損失。

-- 開啟查詢改寫(Session 層級)
SET hg_enable_query_rewrite = on;

-- DB 層級設定(不推薦)
ALTER DATABASE <db_name> SET hg_enable_query_rewrite = on;

為 Dynamic Table 開啟查詢改寫

建立 Dynamic Table 時,通過屬性 allowed_to_rewrite_query 控制該表是否參與查詢改寫;未設定時,預設不參與改寫。

CREATE [ OR REPLACE ] DYNAMIC TABLE [ IF NOT EXISTS ] [<schema_name>.]<table_name> (
  [col_name],
  [col_name],
  [col_name]
)
[LOGICAL PARTITION BY LIST(<partition_key>)]
WITH (
  ...,
  allowed_to_rewrite_query = '[true | false]',
  ...
)
AS
<query>;

參數說明:

  • allowed_to_rewrite_query:標記此 Dynamic Table 是否允許作為“查詢改寫候選”;

    • 'true':允許被查詢改寫使用;

    • 'false':預設值,不參與查詢改寫;

使用建議:

  • 專門用於加速彙總查詢的 DT:設定為 'true'

  • 定義複雜且當前規則無法利用的 DT:設定為 'false',減少最佳化器無效探索。

修改 Dynamic Table 查詢改寫屬性

可通過 ALTER DYNAMIC TABLE ... SET 修改是否參與查詢改寫:

ALTER DYNAMIC TABLE [IF EXISTS] [<schema_name>.]<table_name>
SET (allowed_to_rewrite_query = '[true | false]');

控制查詢改寫命中的 Dynamic Table

存在多個 Dynamic Table 時,可在 Hint 中指定候選表集合,縮小最佳化器搜尋範圍並控制優先順序。Hint 用法見 HINT

SELECT /*+HINT query_rewrite_candidates(<schema.dt_name1> <schema.dt_name2> ...) */
  ...
FROM ...;

GUC使用說明:

  • 若有多個 Dynamic Table,需使用空格分隔;

  • 可指定 schema。

使用樣本:

-- 僅允許 dt_sales 參與查詢改寫
SELECT /*+HINT query_rewrite_candidates(dt_sales) */
  day, hour, min(amount), max(amount)
FROM base_sales_table
GROUP BY day, hour;

支援的功能介紹

目前的版本支援基於單表彙總的查詢改寫,主要包括三種模式:

  • 彙總維度一致的透明改寫;

  • 彙總上卷(Group By 維度上卷彙總);

  • 條件補償的彙總上卷(帶過濾條件的彙總上卷)。

彙總維度一致

適用條件

  • 查詢中的 GROUP BY 維度與 Dynamic Table 定義中的 GROUP BY 維度完全一致;

  • 查詢使用的彙總函式可以由Dynamic Table中已有的彙總結果列直接表示;

  • 彙總函式類型本身不限(包括 DISTINCT),只要Dynamic Table中已經存在對應結果列。

使用樣本

--建立基表
CREATE TABLE base_sales_table(
    day text not null,
    hour int,
    amount int
);
--寫入資料
INSERT INTO base_sales_table
VALUES  ('20250529', 12, 1),
        ('20250529', 12, 2),
        ('20250529', 12, 2),
        ('20250529', 13, 3),
        ('20250530', 13, 4),
        ('20250530', 14, 5),
        ('20250531', 14, 6);

-- Dynamic table
CREATE DYNAMIC TABLE dt_sales
WITH (
    freshness = '1 minutes',
    auto_refresh_mode='incremental',
    auto_refresh_enable='false',
    allowed_to_rewrite_query='true'
)
AS
SELECT
    day,
    hour,
    min(amount),
    max(amount),
    sum(amount),
    count(amount),
    count(*) as rows,
    count(1) as rows1,
    count(distinct amount) as cd
FROM base_sales_table
GROUP BY day, hour;


REFRESH TABLE dt_sales;

查詢樣本:維度一致時,執行計畫中可見基表查詢被改寫為對 Dynamic Table 的查詢。

-- 查詢維度一致
EXPLAIN SELECT day, hour, min(amount), max(amount) FROM base_sales_table GROUP BY day, hour;

彙總維度一致時執行計畫示意

彙總上卷

適用條件

  • Dynamic Table 的 GROUP BY 維度為查詢 GROUP BY 維度超集(即 DT 的維度包含查詢維度);

  • 查詢中的彙總函式可以通過對 DT 已有彙總結果列再彙總得到;

  • 支援的彙總函式:min, max, count, sum, avg

  • 不支援 DISTINCT 彙總上卷(但維度一致情境直接用 DT 中結果列除外)。

彙總函式映射

原始查詢基表的彙總函式

Dynamic Table 中需存在的彙總列

改寫後彙總函式

sum(x)

sum(x)

sum(sum)

count(x)

count(x)

sum(count)

min(x)

min(x)

min(min)

max(x)

max(x)

max(max)

avg(x)

sum(x)count(x)

sum(sum) / sum(count)

使用樣本

--建立基表
CREATE TABLE base_sales_table(
    day text not null,
    hour int,
    amount int
);
--寫入資料
INSERT INTO base_sales_table
VALUES  ('20250529', 12, 1),
        ('20250529', 12, 2),
        ('20250529', 12, 2),
        ('20250529', 13, 3),
        ('20250530', 13, 4),
        ('20250530', 14, 5),
        ('20250531', 14, 6);

-- Dynamic table:為了驗證查詢改寫的效果,先手動關閉自動重新整理
CREATE DYNAMIC TABLE dt_sales
WITH (
    freshness = '1 minutes',
    auto_refresh_mode='incremental',
    auto_refresh_enable='false',
    allowed_to_rewrite_query='true'
)
AS
SELECT
    day,
    hour,
    min(amount),
    max(amount),
    sum(amount),
    count(amount),
    count(*) as rows,
    count(1) as rows1,
    count(distinct amount) as cd
FROM base_sales_table
GROUP BY day, hour;

--手動重新整理dynamic table
REFRESH TABLE dt_sales;

查詢樣本 1:按 day 彙總(上卷)。查詢基表時,GROUP BY 列為 Dynamic Table 定義中的子集,可被正常改寫。

-- 原始查詢
EXPLAIN SELECT day, min(amount), max(amount)
FROM base_sales_table
GROUP BY day;

彙總上卷按day執行計畫示意

查詢樣本 2sum + count + avg 上卷。基表查詢使用 avg,Dynamic Table 中有 sumcount,可推匯出 avg,因此可被改寫。

-- 原始查詢
EXPLAIN SELECT day, sum(amount), count(amount), avg(amount)
FROM base_sales_table
GROUP BY day;

sum+count+avg上卷執行計畫示意

條件補償的彙總上卷(帶過濾條件)

適用條件

  • 查詢基表時包含 WHERE 過濾條件,但是Dynamic Table定義中不能有where過濾條件

  • 所有用於where過濾的欄位都需要出現在 Dynamic Table 的 GROUP BY 維度中;

  • 彙總函式僅支援 min, max, count, sum, avg,不支援 DISTINCT。

使用樣本:

--建立基表
CREATE TABLE base_sales_table(
    day text not null,
    hour int,
    amount int
);
--寫入資料
INSERT INTO base_sales_table
VALUES  ('20250529', 12, 1),
        ('20250529', 12, 2),
        ('20250529', 12, 2),
        ('20250529', 13, 3),
        ('20250530', 13, 4),
        ('20250530', 14, 5),
        ('20250531', 14, 6);

-- Dynamic table:為了驗證查詢改寫的效果,先手動關閉自動重新整理
CREATE DYNAMIC TABLE dt_sales
WITH (
    freshness = '1 minutes',
    auto_refresh_mode='incremental',
    auto_refresh_enable='false',
    allowed_to_rewrite_query='true'
)
AS
SELECT
    day,
    hour,
    min(amount),
    max(amount),
    sum(amount),
    count(amount),
    count(*) as rows,
    count(1) as rows1,
    count(distinct amount) as cd
FROM base_sales_table
GROUP BY day, hour;

--手動重新整理dynamic table
REFRESH TABLE dt_sales;

以下樣本中,查詢基表時帶有 WHERE 條件,且過濾欄位均出現在 GROUP BY 中,因此可被改寫。

EXPLAIN SELECT day, sum(amount), count(amount), avg(amount)
FROM base_sales_table
WHERE day > '20250528' AND day <= '20250531'
GROUP BY day;

條件補償彙總上卷執行計畫示意

查看查詢改寫情況

開啟查詢改寫後,可通過以下方式確認當前查詢是否命中了 Dynamic Table。

  1. 通過執行計畫查看:在 EXPLAIN 結果中查看 Scan 運算元掃描的表名,可判斷是否命中了 Dynamic Table。

  2. 通過慢 query 日誌查看改寫情況:在慢 query 日誌 hologres.hg_query_log 表的 extended_info 欄位中會記錄查詢改寫命中的表;若改寫失敗,會包含相關錯誤說明。

select extended_info::json->>'rewrite_query_info' from hologres.hg_query_log where query_id = 'xxxxx';

                                                                                                               ?column?                                                                                                               
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 {"rewrite_failed_dt": [[\"public.dt3\", {\"rewrite_failed_cause\": \"Doesn't include all query required output columns\"}]], \"rewrite_succeeded_and_selected_dt\": [\"public.dt2\"], \"rewrite_succeeded_but_not_selected_dt\": [\"public.dt1\"]}
(1 row)

使用樣本

樣本 1:基表為 Hologres 內表的查詢改寫

基表來自 TPC-H 資料集 lineitem 100G,建表與匯入方法見 一鍵匯入公用資料集。本樣本中 Dynamic Table 為增量重新整理、非分區表。

CREATE DYNAMIC TABLE dt_lineitem_100g_incremental
WITH (
    freshness = '10 minutes',
    auto_refresh_mode='incremental',
    auto_refresh_enable='false',
    allowed_to_rewrite_query='true')
AS 
select
        l_returnflag,
        l_linestatus,
        l_shipdate,
        sum(l_quantity) as sum_qty,
        count(*) as count_order
from
        hologres_dataset_tpch_100g.lineitem
group by
        l_returnflag,
        l_linestatus,
        l_shipdate

--手動重新整理
REFRESH DYNAMIC TABLE dt_lineitem_100g_incremental;

查詢基表:

set hg_enable_query_rewrite = on;
explain 
select
        l_returnflag,
        l_linestatus,
        l_shipdate,
        sum(l_quantity) as sum_qty,
        count(*) as count_order
from
        hologres_dataset_tpch_100g.lineitem
where  l_shipdate =  '1998-12-01' 
group by
        l_returnflag,
        l_linestatus,
        l_shipdate

執行計畫中可以看到查詢被改寫為查詢DT:

樣本1查詢改寫為DT執行計畫示意

查詢基表的結果如下:

 l_returnflag | l_linestatus | l_shipdate | sum_qty  | count_order 
--------------+--------------+------------+----------+-------------
 N            | O            | 1998-12-01 | 52841.00 |        2070
(1 row)

直接查詢 Dynamic Table(本樣本關閉了自動重新整理,僅做了一次手動重新整理),結果與最近一次重新整理一致:

select
        l_returnflag,
        l_linestatus,
        l_shipdate,
        sum_qty,
        count_order
from
        dt_lineitem_100g_incremental
where  l_shipdate =  '1998-12-01' ;

 l_returnflag | l_linestatus | l_shipdate | sum_qty  | count_order 
--------------+--------------+------------+----------+-------------
 N            | O            | 1998-12-01 | 52841.00 |        2070
(1 row)

樣本 2:基表是 Paimon 外表的查詢改寫

當基表為 Paimon 外表時,同樣可命中查詢改寫。樣本步驟如下:

  1. 準備 Paimon 表:樣本在 Paimon 中匯入 TPC-H customer 100G 表,匯入方法見 Paimon Table

  2. 在 Hologres 中建立 Paimon 外表:需使用 Foreign Table 方式建立,詳見 基於DLF訪問Paimon Catalog

-- 建立 foreign server
CREATE SERVER IF NOT EXISTS paimon_server FOREIGN DATA WRAPPER dlf_fdw OPTIONS (
    catalog_type 'paimon',
    metastore_type 'dlf-rest', 
    dlf_catalog '<dlf_catalog_name>'
);

-- 使用IMPORT FOREIGN SCHEMA建立paimon外表
IMPORT FOREIGN SCHEMA <schema_name>
limit to (customer) 
FROM SERVER paimon_server into public
options (if_table_exist 'update');

--查詢資料
SELECT * FROM customer

建立 Dynamic Table 增量消費 Paimon 外表:在 Hologres 中建立 Dynamic Table,以增量重新整理方式消費 Paimon 外表;為便於驗證改寫效果,本樣本關閉自動重新整理。

--建立dynamic table
CREATE DYNAMIC TABLE dt_paimon_customer
WITH (
    freshness = '10 minutes',
    auto_refresh_mode='incremental',
    auto_refresh_enable='false',
    allowed_to_rewrite_query='true')
AS
SELECT
     c_custkey,
     avg(c_acctbal) ,
     sum(c_acctbal) ,
     count(c_acctbal)
FROM customer
group by c_custkey;

--手動重新整理dynamic table
REFRESH DYNAMIC TABLE dt_paimon_customer;

4、查詢 Paimon 外表並開啟查詢改寫。

set hg_enable_query_rewrite = on;

SELECT
     c_custkey,
     avg(c_acctbal) ,
     sum(c_acctbal) ,
     count(c_acctbal)
FROM
   customer
group by c_custkey ORDER BY 3 DESC  LIMIT 3;

c_custkey	| avg	        |sum	    |count
----------|-------------|---------|-----

3605586	  |9999.990000  |	9999.99	|1
10705496	|9999.990000	|9999.99	|1
14959900	|9999.990000	|9999.99	|1

查詢 Dynamic Table:結果為最近一次重新整理後的資料。

SELECT * FROM dt_paimon_customer ORDER BY 3 DESC  LIMIT 3;

c_custkey	| avg	        |sum	    |count
----------|-------------|---------|-----
3605586	  |9999.990000  |	9999.99	|1
10705496	|9999.990000	|9999.99	|1
14959900	|9999.990000	|9999.99	|1

通過執行計畫確認:可看到查詢已改寫為訪問 Dynamic Table。

樣本2查詢改寫為DT執行計畫示意