即時物化視圖將對明細表的資料進行預先彙總,儲存為物化視圖,通過查詢物化視圖,減少計算量,顯著提升查詢效能。本文為您介紹在Hologres中如何使用物化視圖。
背景資訊
Hologres即時物化視圖不需要手動重新整理物化資料,明細表即時寫入,會即時反映在對物化視圖的查詢上,寫入即可見,寫入即彙總。
在即時物化視圖中,即時寫入的表叫明細表,也稱Base Table,使用者的Insert、Update、Delete都執行在明細表上,物化視圖基於明細表的彙總規則定義,當明細表發生變更時,變更會即時同步到物化視圖中。當前僅支援Insert類變更,後續會逐步增加更多類型的變更。
使用限制
當前即時物化視圖不支援對明細表進行Delete或Update操作,所以需要將明細表設定
appendonly
屬性,當前對明細表任何的Delete或Update操作會提示:Table XXX is append-only
。Flink即時寫入時mutateType
也只支援InsertOrIgnore。當前不支援非同步建立物化視圖,需要建立明細表的同時建立基於該表的物化視圖。
當前僅支援單表的物化視圖,不支援CTE、多表JOIN、子查詢、不支援WHERE條件、ORDER BY、LIMIT、HAVING語句。
即時物化視圖的GROUP BY Key和Value都不支援運算式,比如不支援
SUM(CASE WHEN COND THEN A ELSE B END)
、SUM(col1 + col2)
、GROUP BY date_trunc('hour', ts)
。每張明細表最多建立10個物化視圖,物化視圖數量和資源消耗成正比。
如果基於分區表建立物化視圖,物化視圖的GROUP BY Key必須包含分區表的分區列,且不能對分區表的子表建立物化視圖,只能針對分區表父表建立。
如果基於分區表建立物化視圖,不支援
ATTACH PARTITION
至父表文法,支援CREATE TABLE PARTITION OF
文法。對於建立了物化視圖的明細表,暫不支援
DROP COLUMN
。物化視圖的底層資料與明細表的TTL一致,不可以手動設定物化視圖的TTL,否則會出現物化視圖資料和明細表資料不一致的情況。
支援的彙總函式
物化視圖當前支援如下彙總函式。
SUM
COUNT
AVG
MIN
MAX
RB_BUILD_CARDINALITY_AGG(只支援BIGINT,需建立Extension roaringbitmap)
SQL樣本
建立即時物化視圖
BEGIN; CREATE TABLE base_sales( day text not null, hour int , ts timestamptz, amount float, pk text not null primary key ); CALL SET_TABLE_PROPERTY('base_sales', 'mutate_type', 'appendonly'); --當即時物化視圖被Drop後,可以取消明細表的appendonly屬性,執行以下命令 --CALL SET_TABLE_PROPERTY('base_sales', 'mutate_type', 'none'); CREATE MATERIALIZED VIEW mv_sales AS SELECT day, hour, avg(amount) AS amount_avg FROM base_sales GROUP BY day, hour; COMMIT; insert into base_sales values(to_char(now(),'YYYYMMDD'),'12',now(),100,'pk1'); insert into base_sales values(to_char(now(),'YYYYMMDD'),'12',now(),200,'pk2'); insert into base_sales values(to_char(now(),'YYYYMMDD'),'12',now(),300,'pk3');
分區表建立物化視圖
BEGIN; CREATE TABLE base_sales_p( day text not null, hour int, ts timestamptz, amount float, pk text not null, primary key (day, pk) ) partition by list(day); CALL SET_TABLE_PROPERTY('base_sales_p', 'mutate_type', 'appendonly'); --day是分區列,要出現在視圖的group by的條件中 CREATE MATERIALIZED VIEW mv_sales_p AS SELECT day, hour, avg(amount) AS amount_avg FROM base_sales_p GROUP BY day, hour; COMMIT; create table base_sales_20220101 partition of base_sales_p for values in('20220101');
查詢物化視圖
SELECT * FROM mv_sales WHERE day = to_char(now(),'YYYYMMDD') AND hour = 12;
刪除物化視圖
DROP MATERIALIZED VIEW mv_sales;
查詢物化視圖佔用儲存空間
select pg_relation_size('mv_sales');
查詢所有物化視圖底層佔用空間
SELECT schemaname || '.' || matviewname AS mv_full_name, pg_size_pretty(pg_relation_size('"' || schemaname || '"."' || matviewname || '"')) AS mv_size, pg_relation_size('"' || schemaname || '"."' || matviewname || '"') AS order_size FROM pg_matviews ORDER BY order_size DESC;
使用物化視圖提升精確UV計算效能
精確UV計算是計算複雜度非常高的運算元,通常是系統的效能瓶頸部分。Hologres支援RB_BUILD_CARDINALITY_AGG
彙總函式,通過利用RoaringBitmap資料結構,可以對BIGINT類資料(通常是表示業務ID欄位)進行物化視圖預彙總,實現UV統計即時去重,可按照如下方式建立物化視圖,當前僅支援BIGINT類欄位的彙總去重。
--UV計算依賴RoaringBitmap資料類型,需要提前建立RoaringBitmap extension
CREATE EXTENSION if not exists roaringbitmap;
BEGIN;
CREATE TABLE base_sales_r(
day text not null,
hour int ,
ts timestamptz,
amount float,
userid bigint,
pk text not null primary key
);
CALL SET_TABLE_PROPERTY('base_sales_r', 'mutate_type', 'appendonly');
CREATE MATERIALIZED VIEW mv_sales_r AS
SELECT
day,
hour,
avg(amount) AS amount_avg,
rb_build_cardinality_agg(userid) as user_count
FROM base_sales_r
GROUP BY day, hour;
COMMIT;
insert into base_sales_r values(to_char(now(),'YYYYMMDD'),'12',now(),100,1,'pk1');
insert into base_sales_r values(to_char(now(),'YYYYMMDD'),'12',now(),200,2,'pk2');
insert into base_sales_r values(to_char(now(),'YYYYMMDD'),'12',now(),300,3,'pk3');
select user_count as UV from mv_sales_r where day = to_char(now(),'YYYYMMDD') AND hour = 12;
通過rb_build_cardinality_agg
計算去重數,mv_sales_r
中user_count
代表userid
去重數,查詢user_count
可獲得去重數。
使用物化視圖支援多維度彙總查詢
假設定義了上述的mv_sales
物化視圖,且明細表base_sales
中當前含有以下詳細資料。
Day | Hour | Amount | PK |
20210101 | 12 | 2 | pk1 |
20210101 | 12 | 4 | pk2 |
20210101 | 13 | 6 | pk3 |
直接查詢sales_mv
將會有如下結果。
postgres=> select * from mv_sales;
day | hour | amount_avg
-----------+---------+--------------
20210101 | 12 | 3
20210101 | 13 | 6
這時如果想更改查詢物化視圖的彙總維度,例如使用維度day進行avg彙總計算,則會得到的會是一個錯誤的結果,因為avg的avg不等於total的avg。
postgres=> select day, avg(amount_avg) from mv_sales group by day;
day | avg
-----------+--------
20210101 | 4.5
這時候一種辦法是再建一張以day為維度進行彙總的物化視圖,但這樣會導致物化視圖的數量膨脹,Hologres提供了一種基於彙總中間狀態的實現,使得使用者僅用一張物化視圖,實現不同維度彙總查詢。這裡以Avg為例,修改彙總檢視的定義如下。
BEGIN;
CREATE TABLE base_sales(
day text not null,
hour int ,
ts timestamptz,
amount float,
pk text not null primary key
);
CALL SET_TABLE_PROPERTY('base_sales', 'mutate_type', 'appendonly');
CREATE MATERIALIZED VIEW mv_sales_partial AS
SELECT
day,
hour,
avg(amount) as avg,
avg_partial(amount) AS amt_avg_partial
FROM base_sales
GROUP BY day, hour;
COMMIT;
原先的avg彙總函式重新定義為avg_partial彙總函式,amount_avg_partial列儲存的是彙總結果的中間狀態,查詢時需要修改查詢函數,將avg彙總函式改寫為avg_final最終彙總函式,聲明是對彙總結果中間狀態的最終彙總。
postgres=> select day, avg(avg) as avg_avg, avg_final(amt_avg_partial) as real_avg from mv_sales_partial group by day;
day | avg_avg | real_avg
-----------+-----------+----------
20210101 | 4.5 | 4
目前支援以下彙總函式及對應的partial彙總函式。
普通彙總函式 | Partial彙總函式 | 最終彙總函式 |
AVG | AVG_PARTIAL | AVG_FINAL |
RB_BUILD_CARDINALITY_AGG | RB_BUILD_AGG | RB_OR_CARDINALITY_AGG |
TTL說明
如果明細表設定了TTL,並建立了物化視圖,那麼在TTL臨界點附近的資料,Hologres無法保證明細表和物化視圖查詢結果的一致性,查詢TTL臨界點附近的物化視圖資料的結果,是個未定義行為。下面以明細表base_sales_table
和物化視圖sales_mv
為例。
為base_sales_table
設定了TTL,如果資料由於TTL到期被回收掉,那麼此時查詢明細表的結果如下所示。
postgres=> SELECT
day,
hour,
avg(amount) AS amount_avg
FROM base_sales
GROUP BY day, hour;
--查詢結果
day | hour | amount_avg
-----------+---------+--------------
20210101 | 12 | 4
20210101 | 13 | 6
但是由於被回收的資料,已經物化到了物化視圖的資料中,所以查詢物化視圖時有可能得到的結果如下。
postgres=> select * from mv_sales;
--查詢結果
day | hour | amount_avg
-----------+---------+--------------
20210101 | 12 | 3
20210101 | 13 | 6
此時查詢結果不一致,建議改進方案如下。
明細表不要設定TTL。
明細表設定TTL,但是物化視圖的GROUP BY含有資料的時間欄位,且查詢物化視圖的時候,不會去查詢在TTL臨界點附近的資料。
明細表建成分區表,不設定TTL,回收資料通過刪除(Drop)分區表來實現。
即時物化視圖使用最佳實務
建表時建議將物化視圖的GROUP BY Key設定為明細表的Distribution Key,這樣能進一步提升資料的壓縮率,提升查詢效能。
查詢時建議將查詢物化視圖時常用的過濾條件,放在GROUP BY Key的前列(符合Clustering Key左匹配原則)。
物化視圖的智能路由
查詢時不需要顯式指定物化視圖表名稱,可以像之前一樣基於基礎資料表進行查詢。如果有匹配的物化視圖表,最佳化器會智能路由到最佳的物化視圖表來加速查詢。在查詢時,物化視圖表的選擇規則如下:
選擇包含所有查詢列或可以通過間接計算得到的物化視圖表。
選擇GROUP BY欄欄位包含原始查詢GROUP BY所有列的物化視圖表。
當有多個物化視圖表符合條件時,選擇GROUP BY欄欄位少的物化視圖表。
當前支援智能路由的彙總函式有SUM、COUNT、MIN和MAX。