Table 与物化视图

Table vs Materialized View

这与我之前提出的关于在(非具体化)视图中存储信息的问题 有关。当用户执行以下操作时,数据将如何存储和检索:

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, name, NOW() as now FROM table
#  "AND UPDATE EVERY..."

NOW() 表达式是否作为值保存到存储中,或者是否有任何函数在查询时为实体化视图求值?物化视图是否与 table 相同,它在存储级别完成了某种 optimizations/refreshing,或者我错过了那条船?

此处的 post 建议(至少从功能上讲)实体化视图可以模拟为 table 和触发器:https://www.materialized.info/.

这取决于您使用的数据库平台。看到你用 'oracle' 标记了它,这是 Oracle 中发生的事情。

“现在”值(在本例中为 '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”列都不会改变。如果我现在为物化视图发出刷新命令,我们实际上是 re-running 定义查询,因此 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 实体化视图的处理,包括定义和实体化视图日志

https://docs.oracle.com/en/database/oracle/oracle-database/19/dwhsg/basic-materialized-views.html#GUID-A7AE8E5D-68A5-4519-81EB-252EAAF0ADFF

物化视图的一些更高级的主题(分区、索引等)以及它们如何与自动查询重写相关

https://docs.oracle.com/en/database/oracle/oracle-database/19/dwhsg/advanced-materialized-views.html#GUID-F7394DFE-7CF6-401C-A312-C36603BEB01B

indexed view(或所谓的 materialized 视图)可以使用普通 table 和触发器进行更改。

您知道在 PostgreSQL 中需要 refresh it if the data of underlying table is changed. In Microsoft SQL Server an indexed view is refresh automatically, but there are many requirements 才能在视图上创建索引。

如果您在索引视图中引用了两个 table,则需要在每个 table 上触发才能使用替代解决方案。此外,人们通常会编写执行速度不快的触发器(例如,一个常见的错误是使用 Row By Agonizing Row 而不是批处理)。

所以,索引视图似乎是为了让我们的生活更轻松,但显然它可以用 table 替换并触发其他人 table 因为最后一个解决方案没有面对第一个的局限性,但它更复杂。

对我来说,PostgreSQL 实现对我们毫无用处我希望我的统计信息在提交事务后是正确的,而不是在调用例程刷新它们时。

我在 SQL 服务器的上下文中使用了各种索引视图以优化不同的情况。我也出于同样的目的使用触发器来预先计算数据。我怀疑使用哪一个没有明确的答案。对我来说,如果你可以使用 indexed view - 使用它并让引擎处理困难的事情。如果您面临一些 RDMS 限制 - 您别无选择,只能使用触发器来预先计算数据。

在 SQL 服务器的上下文中,索引视图的维护成本与拥有索引的成本相似。

我在 Oracle 中广泛使用了物化视图,我可以从那个角度来回答。我想其他数据库的一般原则是相同的,也有微小的变化。

首先,与普通视图相比,物化视图是物理存储。普通视图仅存储查询并在 运行 时间执行查询。因此,如果您在 Mat 视图中存储了当前时间戳,除非您刷新视图,否则它会显示旧值。在oracle中,有几种物化视图的刷新策略,如下所述-

1.手动刷新:MView可以使用标准包按需刷新dbms_snapshot.refresh_mview

2。自动刷新:只要在 MView 底层的 table 中使用“On Commit”

进行了任何更改,MView 就会立即刷新

自动刷新可以有多种类型 -

2.1。 Complete(Full) – 每当基础table被修改时,MView将首先被t运行cated并加载数据。顾名思义就是彻底刷新

2.2。 Fast – 每当基table被修改时,MView中只有更新的记录updated/inserted。我们需要“mvlog”文件来实现“快速”刷新。

2.3。 Force – 它将首先尝试进行“快速”刷新。如果由于某些原因,“快速”刷新失败,那么它将执行“完全”刷新。

因此,结构化实体化视图与物理视图完全相似 table。那么问题来了,我们为什么要创作MV? &毕竟创建物化视图的优势是什么?好了,有趣的部分来了。

通常,当基础 table 包含大量数据时,计算所需的聚合或计算这些 table 之间的连接是昂贵的并且 time-consuming。在这种情况下,查询可能需要几分钟甚至几小时。因此,在物化视图中,可以存储预先计算的聚合和连接,当尝试执行聚合 SQL 查询或在查询中使用相同的连接时,数据库引擎实际上不会在 运行 时执行查询相反,它将获取存储在 Mat 视图中的 pre-computed 结果并将这些结果返回给客户端,这要快得多,因为它可以防止这些计算在 运行 时间发生。那么,引擎如何做到这一点? - Oracle 数据库采用称为查询重写的极其强大的过程来使用物化视图快速回答查询。

查询会经过多次检查以确定它是否是查询重写的候选者。如果查询未通过任何检查,则查询将应用于详细信息 table 而不是实体化视图。这在响应时间和处理能力方面可能代价高昂。

优化器使用两种不同的方法来识别何时根据物化视图重写查询。第一种方法基于将查询的 SQL 文本与实体化视图定义的 SQL 文本进行匹配。如果第一种方法失败,优化器将使用更通用的方法,在查询和具体化视图之间比较连接、选择、数据列、分组列和聚合函数。

这实际上是物化视图的一个非常有用的应用程序,可以将查询速度提高 5X -100X 倍。我可以给你一个真实的例子,在我从事的一个项目中,有几个聚合报告需要每周准备,如果我们在数据仓库 tables 之上使用聚合查询,它使用花几个小时让我们建立这些报告。相反,我们后来所做的是在每周一次的数据仓库加载之后,我们过去常常对 Mat 视图进行完全刷新(使用自动刷新功能),比如每周五晚上,并在这些物化视图上启用查询 re-write(有 pre-aggregated/pre-computed 个结果)。然后我们的报告查询过去是 kick-off 周末通过一个自动化过程,由于 pre-aggerated 的这种优化导致 Mat 视图具有查询 re-write 功能,我们的报告构建时间得到了很多更快,我们能够在周一早上验证所有报告并将其交付给利益相关者而不会出现任何问题,而当我们在没有 Mat 视图的情况下完成先前的流程时,我们总是保持警惕,因为构建过去需要 hours/sometimes 天取决于报告。我们同样对 non-aggregated 报告使用了相同的过程,其中涉及大量与维度和事实 table 的连接。因此,在那些物化视图中,我们过去常常以 de-normalized 格式存储数据,以便构建报告时不需要在 运行 时执行连接。 pre-aggregation 优化为我们带来了 50 倍到 100 倍的收益,而 de-normalized 物化视图过去常常给我们带来 5 倍到 30 倍的收益,具体取决于几个因素。

您可以在 Oracle 文档中阅读实现和语法级别的详细信息。如果需要,很乐意提供更多详细信息,但只是想分享 real-life 第一手 Use-case 来了解如果我们能够在正确的场景中使用它,它会有多大用处。以下是 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 数据库会创建一个内部 table 和至少一个索引,并且可能会创建一个视图,所有这些都在物化视图的模式中。

实体化视图语法如下:

Create materialized view View_Name

Build [Immediate/Deffered]

Refresh [Fast/Complete/Force]

on [Commit/Demand]

as Select ..........;

当在 Master table 中执行 DML 时,oracle 将定义更改的行存储在 MV 日志中并使用它来刷新 MV。它称为快速 refresh.You 可以检查中的行为mlog$_table名称。 MV 也称为快照。使用 select name,table_name,refresh_method from user_snapshots,您可以检查状态。

为了体现主table在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,},...);

列表:Comma-separated 您要刷新的快照列表。 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 不支持触​​发器内的执行命令(以刷新 MV),因为触发器本身是单个事务,而其中的执行命令提交使其在一个事务内进行两次提交。

只读实体化视图上的触发器可能看起来有效 - 但您不能依赖它们起作用。

实体化视图中一行的更新可以作为 DELETE+INSERT 完成。

实体化视图的刷新可能涉及对每一行的删除和插入。

刷新可能涉及截断加上每行的直接路径加载。

(最后两个可能会在某个时候发生,你会失去你的触发器过去所做的一切)”--- 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.

实体化视图是已经 实体化 的视图 - 即预评估并写入 disk/memory。它与视图相比很有价值,因为它允许快速有效地访问数据。

例如,如果您有包含数百万行的大型复杂查询,则可能需要一些时间来加入 table 和 运行 聚合或分析函数等。对于在线系统,用户倾向于如果他们不得不等待 10 秒钟,他们会觉得无聊。一个 MV 允许它是 pre-processed。 (也许过夜,也许每隔几个小时等)

这当然可以通过将数据复制到 table 的过程来完成。然而,MV 是为此目的而设置的,并且有许多智能优化,例如 MV 中只有 updating/inserting 行在基础 tables 中发生了变化......这可能意味着 MV 几乎可以更新根据需要立即。这些额外的功能可能使它们更适合 table 然后在过程或触发器中编写逻辑......但有时过程仍然是一个很好的方法!

所以是的,非常像 MV 的东西可以用 triggers/procedures 编写,但是当 Oracle 内置了对 MV 的支持时,这可能是一种不必要的复杂方法。