pg_ivm

pg_ivm

PostgreSQL增量视图维护扩展模块

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

PostgreSQL

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 开发组

编辑推荐精选

讯飞智文

讯飞智文

一键生成PPT和Word,让学习生活更轻松

讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。

AI办公办公工具AI工具讯飞智文AI在线生成PPTAI撰写助手多语种文档生成AI自动配图热门
讯飞星火

讯飞星火

深度推理能力全新升级,全面对标OpenAI o1

科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。

热门AI开发模型训练AI工具讯飞星火大模型智能问答内容创作多语种支持智慧生活
Spark-TTS

Spark-TTS

一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型

Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。

Trae

Trae

字节跳动发布的AI编程神器IDE

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
咔片PPT

咔片PPT

AI助力,做PPT更简单!

咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。

讯飞绘文

讯飞绘文

选题、配图、成文,一站式创作,让内容运营更高效

讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。

热门AI辅助写作AI工具讯飞绘文内容运营AI创作个性化文章多平台分发AI助手
材料星

材料星

专业的AI公文写作平台,公文写作神器

AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。

openai-agents-python

openai-agents-python

OpenAI Agents SDK,助力开发者便捷使用 OpenAI 相关功能。

openai-agents-python 是 OpenAI 推出的一款强大 Python SDK,它为开发者提供了与 OpenAI 模型交互的高效工具,支持工具调用、结果处理、追踪等功能,涵盖多种应用场景,如研究助手、财务研究等,能显著提升开发效率,让开发者更轻松地利用 OpenAI 的技术优势。

Hunyuan3D-2

Hunyuan3D-2

高分辨率纹理 3D 资产生成

Hunyuan3D-2 是腾讯开发的用于 3D 资产生成的强大工具,支持从文本描述、单张图片或多视角图片生成 3D 模型,具备快速形状生成能力,可生成带纹理的高质量 3D 模型,适用于多个领域,为 3D 创作提供了高效解决方案。

3FS

3FS

一个具备存储、管理和客户端操作等多种功能的分布式文件系统相关项目。

3FS 是一个功能强大的分布式文件系统项目,涵盖了存储引擎、元数据管理、客户端工具等多个模块。它支持多种文件操作,如创建文件和目录、设置布局等,同时具备高效的事件循环、节点选择和协程池管理等特性。适用于需要大规模数据存储和管理的场景,能够提高系统的性能和可靠性,是分布式存储领域的优质解决方案。

下拉加载更多