问题描述
这与我问的Saved View with a timestamp expression上一个问题有关,将信息存储在(未实现的)视图中。用户执行以下操作后,如何存储和检索数据:
CREATED MATERIALIZED VIEW mv AS SELECT person_id,name,NOW() as now FROM table
# is this more-or-less the same as:
# CREATED TABLE tb AS SELECT person_id,NOW() as now FROM table
# "AND UPDATE EVERY..."
是将NOW()
表达式作为值保存到存储中,还是在查询时针对物化视图评估了任何函数?物化视图是否与表相同,表在存储级别进行了某种优化/刷新,还是我错过了表?
此处的这篇文章建议(至少从功能上来说)可以将实体化视图模拟为带有触发器的表:https://www.materialized.info/。
解决方法
这取决于您使用的数据库平台。当您用“ oracle”标记它时,这就是Oracle中发生的情况。
在实例化视图实例化时评估“ now”值(在本例中为“ sysdate”)。这很容易演示
SQL> create materialized view MV as select e.*,sysdate d from emp e;
Materialized view created.
SQL> select * from mv;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO D
---------- ---------- --------- ---------- ------------------- ---------- ---------- ---------- -------------------
7369 SMITH CLERK 7902 17/12/1980 00:00:00 800 20 21/10/2020 12:18:26
7499 ALLEN SALESMAN 7698 20/02/1981 00:00:00 1600 300 30 21/10/2020 12:18:26
7521 WARD SALESMAN 7698 22/02/1981 00:00:00 1250 500 30 21/10/2020 12:18:26
7566 JONES MANAGER 7839 02/04/1981 00:00:00 2975 20 21/10/2020 12:18:26
7654 MARTIN SALESMAN 7698 28/09/1981 00:00:00 1250 1400 30 21/10/2020 12:18:26
7698 BLAKE MANAGER 7839 01/05/1981 00:00:00 2850 30 21/10/2020 12:18:26
7782 CLARK MANAGER 7839 09/06/1981 00:00:00 2450 10 21/10/2020 12:18:26
7788 SCOTT ANALYST 7566 09/12/1982 00:00:00 3000 20 21/10/2020 12:18:26
7839 KING PRESIDENT 17/11/1981 00:00:00 5000 10 21/10/2020 12:18:26
7844 TURNER SALESMAN 7698 08/09/1981 00:00:00 1500 30 21/10/2020 12:18:26
7876 ADAMS CLERK 7788 12/01/1983 00:00:00 1100 20 21/10/2020 12:18:26
7900 JAMES CLERK 7698 03/12/1981 00:00:00 950 30 21/10/2020 12:18:26
7902 FORD ANALYST 7566 03/12/1981 00:00:00 3000 20 21/10/2020 12:18:26
7934 MILLER CLERK 7782 23/01/1982 00:00:00 1300 10 21/10/2020 12:18:26
[wait 10 seconds]
14 rows selected.
SQL> select * from mv;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO D
---------- ---------- --------- ---------- ------------------- ---------- ---------- ---------- -------------------
7369 SMITH CLERK 7902 17/12/1980 00:00:00 800 20 21/10/2020 12:18:26
7499 ALLEN SALESMAN 7698 20/02/1981 00:00:00 1600 300 30 21/10/2020 12:18:26
7521 WARD SALESMAN 7698 22/02/1981 00:00:00 1250 500 30 21/10/2020 12:18:26
7566 JONES MANAGER 7839 02/04/1981 00:00:00 2975 20 21/10/2020 12:18:26
7654 MARTIN SALESMAN 7698 28/09/1981 00:00:00 1250 1400 30 21/10/2020 12:18:26
7698 BLAKE MANAGER 7839 01/05/1981 00:00:00 2850 30 21/10/2020 12:18:26
7782 CLARK MANAGER 7839 09/06/1981 00:00:00 2450 10 21/10/2020 12:18:26
7788 SCOTT ANALYST 7566 09/12/1982 00:00:00 3000 20 21/10/2020 12:18:26
7839 KING PRESIDENT 17/11/1981 00:00:00 5000 10 21/10/2020 12:18:26
7844 TURNER SALESMAN 7698 08/09/1981 00:00:00 1500 30 21/10/2020 12:18:26
7876 ADAMS CLERK 7788 12/01/1983 00:00:00 1100 20 21/10/2020 12:18:26
7900 JAMES CLERK 7698 03/12/1981 00:00:00 950 30 21/10/2020 12:18:26
7902 FORD ANALYST 7566 03/12/1981 00:00:00 3000 20 21/10/2020 12:18:26
7934 MILLER CLERK 7782 23/01/1982 00:00:00 1300 10 21/10/2020 12:18:26
14 rows selected.
无论您查询实例化视图多少次,“ D”列均不会更改。如果现在我为物化视图发出刷新命令,则实际上是在重新运行定义查询,因此sysdate(以及列“ D”列)将在刷新时被提取。
SQL> exec dbms_mview.refresh('MV')
PL/SQL procedure successfully completed.
SQL> select * from mv;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO D
---------- ---------- --------- ---------- ------------------- ---------- ---------- ---------- -------------------
7369 SMITH CLERK 7902 17/12/1980 00:00:00 800 20 21/10/2020 12:19:12
7499 ALLEN SALESMAN 7698 20/02/1981 00:00:00 1600 300 30 21/10/2020 12:19:12
7521 WARD SALESMAN 7698 22/02/1981 00:00:00 1250 500 30 21/10/2020 12:19:12
7566 JONES MANAGER 7839 02/04/1981 00:00:00 2975 20 21/10/2020 12:19:12
7654 MARTIN SALESMAN 7698 28/09/1981 00:00:00 1250 1400 30 21/10/2020 12:19:12
7698 BLAKE MANAGER 7839 01/05/1981 00:00:00 2850 30 21/10/2020 12:19:12
7782 CLARK MANAGER 7839 09/06/1981 00:00:00 2450 10 21/10/2020 12:19:12
7788 SCOTT ANALYST 7566 09/12/1982 00:00:00 3000 20 21/10/2020 12:19:12
7839 KING PRESIDENT 17/11/1981 00:00:00 5000 10 21/10/2020 12:19:12
7844 TURNER SALESMAN 7698 08/09/1981 00:00:00 1500 30 21/10/2020 12:19:12
7876 ADAMS CLERK 7788 12/01/1983 00:00:00 1100 20 21/10/2020 12:19:12
7900 JAMES CLERK 7698 03/12/1981 00:00:00 950 30 21/10/2020 12:19:12
7902 FORD ANALYST 7566 03/12/1981 00:00:00 3000 20 21/10/2020 12:19:12
7934 MILLER CLERK 7782 23/01/1982 00:00:00 1300 10 21/10/2020 12:19:12
14 rows selected.
SQL>
但是每个平台可能都有自己的特征。
此处涵盖了Oracle实例化视图的处理,包括定义和实例化视图日志
以及物化视图的一些更高级的主题(分区,索引等)以及它们如何与自动查询重写相关联
,我在Oracle中广泛使用了物化视图,我可以从这种角度回答。我可以想象,一般的原理对于其他数据库也是一样,只是变化很小。
首先,物化视图与普通视图相比是物理存储。普通视图仅存储查询,并在运行时执行查询。因此,如果您在Mat视图中存储了当前时间戳,则除非刷新视图,否则它将显示旧值。在oracle中,针对物化视图有几种刷新策略,如下所述-
1。手动刷新:可以使用标准软件包dbms_snapshot.refresh_mview
来按需刷新MView。2。自动刷新:只要使用“提交时”在MView底层的表中进行任何更改,就可以刷新MView。
自动刷新可以有多种类型-
2.1。 Complete(Full)(完成(完整))–修改基表后,MView会先被截断并加载数据。顾名思义,它已完全刷新。
2.2。快速 –修改基表时,只有已更新的记录才被更新/插入到MView中。我们需要“ mvlog”文件来进行“快速”刷新。
2.3。强制 –它将首先尝试进行“快速”刷新。如果由于某些原因“快速”刷新失败,则将执行“完整”刷新。
因此,结构化物化视图与物理表完全相似。问题是为什么我们要创建MV?毕竟创建物化视图的好处是什么?好吧,这是有趣的部分。
通常,当基表包含大量数据时,计算所需的聚合或计算这些表之间的联接既昂贵又耗时。在这种情况下,查询可能需要几分钟甚至几小时。因此,在物化视图中,人们可以存储预先计算的聚合和联接,并且当人们尝试执行聚合SQL查询或在查询中使用那些相同的联接时,数据库引擎实际上不会在运行时执行查询,而是会获取预先计算的结果存储在Mat视图上并将这些结果返回给客户端,这更快,因为它可以防止这些计算在运行时发生。那么,引擎如何做到这一点呢? -Oracle数据库采用了一种非常强大的过程,称为查询重写,可以使用实例化视图快速回答查询。
对查询进行几次检查,以确定它是否适合重写查询。如果查询未通过任何检查,则该查询将应用于明细表而不是具体化视图。就响应时间和处理能力而言,这可能是昂贵的。
优化器使用两种不同的方法来根据实体化视图识别何时重写查询。第一种方法基于将查询的SQL文本与实例化视图定义的SQL文本进行匹配。如果第一种方法失败,则优化器将使用更通用的方法,在该方法中,将查询和实例化视图之间的联接,选择,数据列,分组列以及聚合函数进行比较。
此事实是物化视图的非常有用的应用程序,可以将查询速度提高5倍-100倍。我可以举一个真实的例子,在我从事的一个项目中,每周需要准备几份汇总报告,如果我们在数据仓库表的顶部使用汇总查询,则过去需要花费数小时建立那些报告。取而代之,我们后来做的是在每周每批数据仓库负载之后,我们在每个星期五晚上对Mat视图进行完全刷新(使用自动刷新功能),并在这些实例化视图上启用查询重写(具有-汇总/预先计算的结果)。然后,我们的报表查询过去通常是通过自动化流程在周末开始的,并且由于具有查询重写功能的Mat视图中预先夸大的结果的优化,我们的报表生成时间缩短了很多,我们能够可以在星期一早上之前验证所有报告并将其交付给利益相关者,而不会打h,而在没有Mat视图的情况下进行先前的流程时,我们总是会保持警惕,因为构建过去需要花费数小时/有时数天的时间,具体取决于报告。对于未汇总的报告,我们同样使用相同的过程,这涉及到许多带有维和事实表的联接。因此,在那些物化视图中,我们习惯于以非规范化格式存储数据,以便在生成报告时无需在运行时执行联接。进行预聚合优化后,我们获得了50倍至100倍的收益,而经过归一化的物化视图通常会为我们提供5倍至30倍的收益,具体取决于多种因素。
您可以在Oracle文档中阅读实现和语法级别的详细信息。如果需要,我们很乐意提供更多详细信息,但只是想分享一个真实的第一手用例,以阐明如果我们能够在正确的情况下使用它,将有多大用处。以下是Oracle中的示例语法供参考。
CREATE MATERIALIZED VIEW department_mv
refresh complete on commit --Automatic Complete refresh (as described above)
enable query rewrite -- this feature enables optimization (as described above)
as
SELECT deptno,dept_name,SUM(salary)
FROM department
GROUP BY deptno,dept_name;
,
简单来说: SQL中的实例化视图是物理构造,它物理存储在光盘上。但是视图只是逻辑结构,它们是在查询中需要的位置创建的。
创建物化视图时,Oracle数据库将在物化视图的模式中创建一个内部表和至少一个索引,并可能创建一个视图。
以下是实例化视图的语法:
Create materialized view View_Name
Build [Immediate/Deffered]
Refresh [Fast/Complete/Force]
on [Commit/Demand]
as Select ..........;
在主表中执行DML时,oracle将定义更改的行存储在MV日志中,并使用它来刷新MV。这称为快速刷新。您可以在mlog $ _tablename中检查行为。
MV也称为快照。使用select name,table_name,refresh_method from user_snapshots
,您可以检查状态。
要反映MV中主表的更改,请执行以下操作:
execute DBMS_MVIEW.REFRESH('name_of the view');
对于单个快照:
execute DBMS_SNAPSHOT.REFRESH( 'v_materialized_foo_tbl','f')
;
刷新程序 以下过程刷新了快照列表。
语法
DBMS_SNAPSHOT.REFRESH (
{ list IN VARCHAR2,| tab IN OUT DBMS_UTILITY.UNCL_ARRAY,},...);
list:要刷新的快照的逗号分隔列表。
tab:一串刷新方法,指示如何刷新列出的快照。 F' or
f'表示快速刷新,?' indicates force refresh,
C'或c' indicates complete refresh,and
A'或'a'表示始终刷新,
因此,当您通过execute DBMS_MVIEW.REFRESH()
或DBMS_SNAPSHOT.REFRESH
刷新它时,将调用NOW()的值
尽管在MV上可以使用mysql,但是在MV上使用触发器并不是一个好习惯。 Oracle不支持触发器内的Execute命令(以刷新MV),因为触发器本身是单个事务,而执行命令的提交使其在一个事务内两次提交。
Does an insert trigger need a commit statement
在只读的物化视图上触发似乎有效-但您不能依靠它们起作用。
在物化视图中更新行可以通过DELETE + INSERT完成。
刷新实例化视图可能需要删除并插入每一行。
刷新可能会涉及到截断以及Ever行的直接路径加载。
(最后两个可能会在某个时间发生,您将失去触发器过去所做的任何事情)”- https://asktom.oracle.com/pls/apex/asktom.search%3Ftag%3Dtriggers-on-materialized-views#:~:text=Triggers%20on%20a%20read%20only,delete%20%2B%20insert%20of%20every%20row。
,可以使用普通表和触发器来更改indexed view
(或称为materialized
视图)。
您知道在PostgreSQL中如果基础表的数据已更改,则需要refresh。在Microsoft SQL Server中,索引视图会自动刷新,但是要在视图上创建索引,需要执行many requirements。
如果在索引视图中引用了两个表,则需要在每个表上触发才能使用替代解决方案。同样,人们编写的触发器执行不快速也是很常见的(例如,一个常见的错误是使用Row By Agonizing Row而不是批处理)。
因此,似乎可以使用索引视图来使我们的生活变得更轻松,但显然,可以将其替换为表并触发其他表,因为最后一种解决方案没有面临第一个解决方案的局限,但更为复杂。
对我来说,PostgreSQL实现是无用的,我希望我的统计信息在提交事务后才是正确的,而不是在调用例程以刷新它们时是正确的。
为了优化不同的情况,我在SQL Server的上下文中使用了各种索引视图。我也出于相同的目的使用触发器来预先计算数据。我怀疑有确切的答案使用哪个。对我来说,如果可以使用indexed view
-使用它,然后离开引擎来处理困难的事情。如果您面临RDMS的一些限制-您别无选择,只能使用触发器来预先计算数据。
在SQL Server的上下文中,索引视图的维护成本类似于拥有索引的成本。
,实例化视图是已经 实例化 的视图-即已预先评估并写入磁盘/内存。与视图相比,它很有价值,因为它可以快速有效地访问数据。
例如,如果您有数百万行的大型复杂查询,则可能需要一些时间才能连接表并运行聚合或分析功能等。对于在线系统,用户必须等待10秒钟才会感到无聊。 MV允许对此进行预处理。 (也许一整夜,也许每隔几个小时等)
这当然可以通过将数据复制到表的过程来完成。但是,MV是为此目的而设置的,并且具有许多智能优化功能,例如仅更新/插入了基础表中已更改的MV中的行...这可能意味着MV几乎可以根据需要立即更新。这些额外的功能可能使它们更适合于在过程或触发器中编写逻辑,但是有时该过程仍然是一个不错的选择!
是的,可以使用触发器/过程编写非常类似于MV的内容,但是当Oracle内置了对MV的支持时,这可能是不必要地复杂的事情。