Project Icon

pg_ivm

PostgreSQL增量视图维护扩展模块

pg_ivm是PostgreSQL的增量视图维护扩展模块,支持物化视图实时更新而无需完全重新计算。兼容PostgreSQL 13至17版本,支持内连接、DISTINCT、部分聚合函数和简单子查询。通过自动创建触发器和索引,pg_ivm可在基表更新时高效维护物化视图,适用于频繁查询但更新较少的场景。该模块为物化视图提供了更灵活和高效的维护方式。

pg_ivm

pg_ivm模块为PostgreSQL提供增量视图维护(IVM)功能。 该扩展与PostgreSQL 13、14、15、16和17版本兼容。

描述

**增量视图维护(IVM)**是一种使物化视图保持最新的方法,它只计算并应用视图的增量变化,而不像REFRESH MATERIALIZED VIEW那样从头重新计算内容。当视图只有小部分发生变化时,IVM比重新计算更有效地更新物化视图。

关于视图维护的时机,有两种方法:即时维护和延迟维护。在即时维护中,视图在其基表被修改的同一事务中更新。在延迟维护中,视图在事务提交后更新,例如,在访问视图时,响应用户命令如REFRESH MATERIALIZED VIEW,或定期在后台更新等。pg_ivm提供了一种即时维护方式,即当基表被修改时,物化视图立即在AFTER触发器中更新。

我们将支持IVM的物化视图称为增量可维护物化视图(IMMV)。要创建IMMV,你需要使用关系名称和视图定义查询调用create_immv函数。例如:

SELECT create_immv('myview', 'SELECT * FROM mytab');

这将创建一个名为'myview'的IMMV,定义为SELECT * FROM mytab。这相当于以下创建普通物化视图的命令:

CREATE MATERIALIZED VIEW myview AS SELECT * FROM mytab;

当创建IMMV时,会自动创建一些触发器,以便在其基表被修改时立即更新视图的内容。

postgres=# SELECT create_immv('m', 'SELECT * FROM t0');
注意:无法自动在immv "m"上创建索引
详细信息:此目标列表没有包含所有主键列,或此视图不包含DISTINCT子句。
提示:在immv上创建索引以实现高效的增量维护。
create_immv
-------------
3
(1行)

postgres=# SELECT * FROM m;
i
---
1
2
3
(3行)

postgres=# INSERT INTO t0 VALUES (4);
INSERT 0 1
postgres=# SELECT * FROM m; -- 自动更新
i
---
1
2
3
4
(4行)

请注意,如果你使用PostgreSQL 17或更高版本,在IMMV的自动维护期间,search_path会暂时更改为pg_catalog, pg_temp

安装

要安装pg_ivm,请在模块目录中执行以下命令:

make install

如果您是通过rpm或deb安装的PostgreSQL,则需要开发包(例如,postgresql14-devel或postgresql-server-dev-14)。

重要提示: 如果您想在非默认或自定义构建的PostgreSQL上使用pg_ivm,请不要忘记设置PG_CONFIG变量(make PG_CONFIG=...)或将pg_config命令的路径添加到PATH中。更多信息请参阅这里。 然后,执行CREATE EXTENSION命令。

CREATE EXTENSION pg_ivm;

RPM包和yum仓库

pg_ivm的RPM包可以从PostgreSQL yum仓库获取。详细信息请参阅说明。请注意,我们不是该yum仓库的维护者,其中的pg_ivm RPM包可能并非总是最新版本。

对象

当安装了pg_ivm后,将创建以下对象。

函数

create_immv

使用create_immv函数创建IMMV。

create_immv(immv_name text, view_definition text) RETURNS bigint

create_immv定义一个新的查询IMMV。它会创建一个名为immv_name的表,执行由view_definition指定的查询,并用结果填充IMMV。该查询会被存储在pg_ivm_immv中,以便之后进行增量视图维护时刷新。create_immv返回创建的IMMV中的行数。

创建IMMV时,系统会自动创建一些触发器,以便在基表被修改时立即更新视图内容。此外,如果可能的话,还会自动为IMMV创建一个唯一索引。如果视图定义查询有GROUP BY子句,则会在GROUP BY表达式的列上创建唯一索引。如果视图有DISTINCT子句,则会在目标列表的所有列上创建唯一索引。否则,如果IMMV的目标列表中包含其基表的所有主键属性,则会在这些属性上创建唯一索引。在其他情况下,不会创建索引。

注意,如果你使用PostgreSQL 17或更高版本,在create_immv运行期间,search_path会临时更改为pg_catalog, pg_temp

refresh_imm

使用refresh_immv函数刷新IMMV。

refresh_immv(immv_name text, with_data bool) RETURNS bigint

refresh_immv完全替换IMMV的内容,就像REFRESH MATERIALIZED VIEW命令对物化视图所做的那样。要执行此函数,你必须是IMMV的所有者(在PostgreSQL 16或更早版本中)或对IMMV拥有MAINTAIN权限(在PostgreSQL 17或更高版本中)。旧内容将被丢弃。

with_data标志对应于REFRESH MATERIALIZED VIEW命令的WITH [NO] DATA选项。如果with_data为true,将执行后台查询以提供新数据,如果IMMV未填充,则创建用于维护视图的触发器。此外,如果可能且视图尚未拥有,还会为IMMV创建唯一索引。如果with_data为false,则不会生成新数据,IMMV将变为未填充状态,并且会从IMMV中删除触发器。注意,未填充的IMMV仍然可以扫描,尽管结果为空。这种行为在将来可能会改变,当扫描未填充的IMMV时可能会引发错误。

注意,如果你使用PostgreSQL 17或更高版本,在refresh_immv运行期间,search_path会临时更改为pg_catalog, pg_temp

get_immv_def

get_immv_def重构IMMV的底层SELECT命令。(这是一个反编译重构,而不是命令的原始文本。)

get_immv_def(immv regclass) RETURNS text

IMMV元数据目录

目录pg_ivm_immv存储IMMV信息。

名称类型描述
immvrelidregclassIMMV的OID
viewdeftext视图定义的查询树(以nodeToString()表示形式)
ispopulatedbool如果IMMV当前已填充则为True

示例

总的来说,IMMV允许比REFRESH MATERIALIZED VIEW更快的更新,但代价是对其基表的更新速度较慢。基表更新较慢是因为需要触发触发器,并且IMMV在每个修改语句的触发器中更新。

例如,假设有一个如下定义的普通物化视图:

test=# CREATE MATERIALIZED VIEW mv_normal AS
SELECT a.aid, b.bid, a.abalance, b.bbalance
FROM pgbench_accounts a JOIN pgbench_branches b USING(bid);
SELECT 10000000

更新这个物化视图的基表中的一个元组很快,但对这个视图执行REFRESH MATERIALIZED VIEW命令需要很长时间:

test=# UPDATE pgbench_accounts SET abalance = 1000 WHERE aid = 1;
UPDATE 1
Time: 9.052 ms

test=# REFRESH MATERIALIZED VIEW mv_normal ;
REFRESH MATERIALIZED VIEW
Time: 20575.721 ms (00:20.576)

另一方面,使用相同的视图定义创建IMMV后:

test=# SELECT create_immv('immv',
'SELECT a.aid, b.bid, a.abalance, b.bbalance
FROM pgbench_accounts a JOIN pgbench_branches b USING(bid)');
NOTICE:  created index "immv_index" on immv "immv"
create_immv
-------------
10000000
(1 row)

更新基表中的一个元组比普通视图需要更多时间,但其内容会自动更新,这比REFRESH MATERIALIZED VIEW命令更快。

test=# UPDATE pgbench_accounts SET abalance = 1234 WHERE aid = 1;
UPDATE 1
Time: 15.448 ms

test=# SELECT * FROM immv WHERE aid = 1;
aid | bid | abalance | bbalance
-----+-----+----------+----------
1 |   1 |     1234 |        0
(1 row)

IMMV上的适当索引对于高效的IVM是必要的,因为我们需要在IMMV中查找要更新的元组。如果没有索引,将会花费很长时间。

因此,当通过create_immv函数创建IMMV时,如果可能,会自动在其上创建唯一索引。如果视图定义查询有GROUP BY子句,会在GROUP BY表达式的列上创建唯一索引。此外,如果视图有DISTINCT子句,会在目标列表中的所有列上创建唯一索引。否则,如果IMMV在目标列表中包含其所有基表的主键属性,会在这些属性上创建唯一索引。在其他情况下,不会创建索引。

在前面的例子中,在"immv"的aid和bid列上创建了一个名为"immv_index"的唯一索引,这使得视图的快速更新成为可能。删除这个索引会使更新视图花费更长的时间。

test=# DROP INDEX immv_index;
DROP INDEX

test=# UPDATE pgbench_accounts SET abalance = 9876 WHERE aid = 1;
UPDATE 1
Time: 3224.741 ms (00:03.225)

支持的视图定义和限制

目前,IMMV的视图定义可以包含内连接、DISTINCT子句、一些内置聚合函数、FROM子句中的简单子查询、EXISTS子查询和简单的CTE(WITH查询)。支持包括自连接在内的内连接,但不支持外连接。支持的聚合函数有count、sum、avg、min和max。其他聚合函数、包含聚合或DISTINCT子句的子查询、FROM子句以外的子查询、窗口函数、HAVINGORDER BYLIMIT/OFFSETUNION/INTERSECT/EXCEPTDISTINCT ONTABLESAMPLEVALUES以及FOR UPDATE/SHARE不能在视图定义中使用。

基表必须是简单表。不能使用视图、物化视图、继承父表、分区表、分区和外部表。

视图定义查询中不能包含任何系统列。

目标列表不能包含以__ivm_开头的列名。

视图目标列表中使用的数据类型必须具有btree访问方法的默认运算符类。例如,jsonxmlpoint类型不能出现在目标列表中。

不支持逻辑复制,也就是说,即使发布节点上的基表被修改,订阅节点上基于这些基表定义的IMMV也不会更新。

注意事项

聚合函数

支持的聚合函数包括countsumavgminmax。目前仅支持内置聚合函数,不能使用用户自定义聚合。

当创建包含聚合的IMMV时,一些以__ivm开头的额外列会自动添加到目标列表中。__ivm_count__包含每个分组中聚合的元组数。此外,还会为每个聚合值列添加多个额外列以维护其值。例如,为维护平均值会添加名为__ivm_count_avg____ivm_sum_avg__的列。当基表被修改时,新的聚合值会使用旧的聚合值和存储在IMMV中相关额外列的值进行增量计算。

注意,对于minmax,当包含当前最小或最大值的元组从基表中删除时,可能需要从基表重新计算受影响分组的新值。因此,更新包含这些函数的IMMV可能需要较长时间。

另外,在IMMV中对realfloat4)类型或double precisionfloat8)类型使用sumavg是不安全的,因为由于这些类型的精度有限,IMMV中的聚合值可能与从基表计算的结果不同。为避免此问题,请使用numeric类型。

聚合的限制

如果有GROUP BY子句,GROUP BY中指定的表达式必须出现在目标列表中。这是用于识别IMMV中需要更新的元组的方式。这些属性用作搜索IMMV中元组的扫描键,因此需要在它们上建立索引以实现高效的IVM。

目标列表不能包含含有聚合的表达式。

子查询

支持FROM子句中的简单子查询和WHERE子句中的EXISTS子查询。

子查询的限制

支持使用EXISTS的子查询和FROM子句中的简单子查询。不支持除'AND'以外条件的EXISTS子查询和目标列表中的子查询。EXISTS子查询仅支持在WHERE中使用,不支持在目标列表中使用。

如果EXISTS包含引用外部查询表中列的列,这些列必须包含在目标列表中。

不支持包含聚合函数或DISTINCT的子查询。

CTE

支持简单的CTE(WITH查询)。

CTE的限制

不支持包含聚合函数或DISTINCTWITH查询。

不允许递归查询(WITH RECURSIVE)。也不允许未引用的CTE,即CTE必须在视图定义查询中至少被引用一次。

DISTINCT

IMMV的定义查询中允许使用DISTINCT。假设在包含重复元组的基表上定义了带DISTINCT的IMMV。当从基表删除元组时,只有当元组的重复数变为零时,视图中的元组才会被删除。此外,当向基表插入元组时,只有当视图中不存在相同的元组时,才会向视图中插入元组。

从物理上讲,使用DISTINCT定义的IMMV包含消除重复后的元组,每个元组的重复数存储在创建此类IMMV时添加的名为__ivm_count__的额外列中。

TRUNCATE

当基表被截断时,如果视图定义查询不包含没有GROUP BY子句的聚合,IMMV也会被截断,内容变为空。没有GROUP BY子句的聚合视图始终有一行。因此,在这种情况下,如果基表被截断,IMMV只会被刷新而不是被截断。

并发事务

假设一个IMMV定义在两个基表上,每个表在不同的并发事务中同时被修改。在先提交的事务中,IMMV可以只考虑该事务中发生的变化进行更新。另一方面,为了在后提交的事务中正确更新IMMV,我们需要知道两个事务中发生的变化。因此,在READ COMMITTED模式下,一旦基表被修改,就会立即在IMMV上持有ExclusiveLock,以确保IMMV在后一个事务中在前一个事务提交后更新。在REPEATABLE READSERIALIZABLE模式下,如果锁获取失败,会立即引发错误,因为在这些模式下其他事务中发生的任何变化都不可见,在这种情况下IMMV无法正确更新。但是,作为例外,如果IMMV只有一个基表且不使用DISTINCT或GROUP BY,并且表通过INSERT修改,那么在IMMV上持有的锁是RowExclusiveLock

行级安全性

如果某些基表有行级安全策略,对物化视图所有者不可见的行将从结果中排除。此外,在视图增量维护时,这些行也会被排除。然而,如果在创建物化视图后定义了新策略或更改了策略,新策略不会应用于视图内容。要应用新策略,需要重新创建IMMV。

如何禁用或启用即时维护

当我们希望保持IMMV最新,且基表的小部分不频繁修改时,IVM是有效的。由于即时维护的开销,当基表频繁修改时IVM不太有效。此外,当修改基表的大部分或向基表插入大量数据时,IVM不太有效,维护成本可能大于从头刷新。

在这种情况下,我们可以在修改基表之前使用refesh_immv函数,并将with_data设为false来禁用即时维护。修改基表后,调用refresh_immv并将with_data设为true来刷新视图数据并启用即时维护。

作者

IVM 开发团队

许可证

PostgreSQL 许可证

版权声明

  • 部分版权所有 © 1996-2022,PostgreSQL 全球开发组
  • 部分版权所有 © 2022,IVM 开发组
项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

稿定AI

稿定设计 是一个多功能的在线设计和创意平台,提供广泛的设计工具和资源,以满足不同用户的需求。从专业的图形设计师到普通用户,无论是进行图片处理、智能抠图、H5页面制作还是视频剪辑,稿定设计都能提供简单、高效的解决方案。该平台以其用户友好的界面和强大的功能集合,帮助用户轻松实现创意设计。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号