您可以在创建物化视图时指定刷新模式或者手动刷新物化视图。

权限要求
  • 需要物化视图INSERT权限。
  • 需要有物化视图所涉及的所有基表相关列(或整个表)的SELECT权限。
  • 如果要启用自动刷新功能,需要创建者在 127.0.0.1 上有刷新视图的权限。因为系统会代理创建者身份,从服务器本地(127.0.0.1)登录来执行自动刷新。这样当创建者没有权限之后,系统也无法刷新,避免越权问题。如果用户权限是在所有IP上 ('%'),那么就不会产生这个问题,因为所有IP也包括了 127.0.0.1。
创建时指定刷新模式

物化视图刷新分为全量刷新(COMPLETE)和增量刷新(FAST)两种刷新模式。如果未指定刷新模式,默认为全量刷新。

每种刷新模式适用于不同的触发方式。

CREATE MATERIALIZED VIEW mv_name
[REFRESH [FAST|COMPLETE] [ON <DEMAND|OVERWRITE>] [START WITH date] [NEXT date]]
说明 目前仅支持全量刷新(COMPLETE)。
手动刷新
# 手动触发一次刷新
REFRESH MATERIALIZED VIEW <mv_name>

全量刷新模式

创建物化视图时默认为全量刷新模式。全量刷新会计算刷新时刻的查询结果,并且用覆盖的方式替换原来的结果。

全量刷新触发机制
ON DEMAND:按需刷新。按需刷新要么用户手动触发刷新,要么自动刷新。全量刷新默认采用按需刷新(ON DEMAND)。
# 手动刷新
CREATE MATERIALIZED VIEW my_mv
REFRESH ON DEMAND
AS
SELECT * FROM base

# 自动刷新 (5分钟后第一次刷新,此后每分钟1次)
CREATE MATERIALIZED VIEW my_mv
REFRESH ON DEMAND START WITH now() + interval 5 minute NEXT now() + interval 1 minute
AS
SELECT * FROM base
ON OVERWRITE:当基表被INSERT OVERWRITE覆写后,会触发对应物化视图的刷新。适合T+1场景,在数据清洗覆盖后自动更新物化视图。
# 创建
CREATE MATERIALIZED VIEW my_mv
REFRESH ON OVERWRITE
AS
SELECT * FROM base

# 触发 my_mv 刷新
INSERT OVERWRITE base SELECT * FROM t0; 
全量刷新原子性说明

物化视图使用和普通表一样的存储结构。AnalyticDB采用分布式存储,表数据存储在多个分区上,分区散落在多台机器上,通过HASH的方式将数据分区(通过 DISTRIBUTED BY HASH 关键字指定分区列)。

全量刷新保证每个分区是原子替换的。这意味着,任意一个分区,要么是刷新前的数据,要么是刷新后的数据,不存在中间状态。但是,由于有多个分区同时替换,刷新时可能有一瞬间,某些分区是刷新后的结果,而某些分区没有替换好,还是旧数据。

如果需要严格保证整张物化视图所有分区数据是在一个原子操作内替换,可以提工单申请,单独配置原子刷新模式。该模式开销较大,默认不启用。

自动刷新

自动刷新支持使用时间函数(START WITH ... NEXT)来设置刷新规律。START WITH是可选的,默认从当前时刻开始。

# 每周一晚上2点刷新
CREATE MATERIALIZED VIEW myview
REFRESH 
 START WITH DATE_FORMAT(now() + interval 7 - weekday(now()) day, '%Y-%m-%d 02:00:00') 
 NEXT DATE_FORMAT(now() + interval 7 - weekday(now()) day, '%Y-%m-%d 02:00:00')
AS
SELECT count(*) as cnt FROM base

# 每天晚上夜里2点刷新
CREATE MATERIALIZED VIEW myview
REFRESH 
 START WITH DATE_FORMAT(now() + interval 1 day, '%Y-%m-%d 02:00:00')
 NEXT DATE_FORMAT(now() + interval 1 day, '%Y-%m-%d 02:00:00')
AS
SELECT count(*) as cnt FROM base

# 每个月第一天凌晨2点刷新
CREATE MATERIALIZED VIEW myview
REFRESH NEXT DATE_FORMAT(last_day(now()) + interval 1 day, '%Y-%m-%d 02:00:00')
AS
SELECT count(*) as cnt FROM base

# 只刷一次
CREATE MATERIALIZED VIEW myview
REFRESH START WITH now() + interval 1 day
AS 
SELECT count(*) as cnt FROM base

如果某次刷新所用的时间超过自动刷新指定的间隔,会自动跳过超过的时间点,等到下次最近的时间点再刷新。

假设自动刷新设置是在 00:05:00, 00:10:00, 00:15:00 这3个时间点,间隔5分钟。如果 00:05:00 时候开始了某次刷新,一直到00:12:00刷新才结束,那么设置的 00:10:00 刷新会被跳过,直到 00:15:00 再开始刷新。