【问题标题】:Does a redshift materialized view refresh lock the base tables?红移物化视图刷新是否会锁定基表?
【发布时间】:2021-11-02 21:49:15
【问题描述】:

正如标题所示,我不确定refresh materialized view 命令是否会锁定基表(即不允许读写)。文档没有建议,而且我认为它不需要考虑它只是读取它们然后更新事务中的视图。但是,我在刷新期间始终遇到可序列化的隔离违规,因此我试图找出导致这种情况的原因。

附加上下文:

  1. 我们有一个具有四个基表的系统,物化视图在刷新时从中读取。我们全天通过copy command 插入这些基表。 AWS Firehose 执行复制查询,定期从 S3 加载数据(json 格式)。这些插入几乎不断发生。可能至少每 5 分钟 1 次。
  2. 物化视图刷新大约需要 7 分钟才能完成,每 10 分钟刷新一次。可能每 4 次执行中就有 1 次会失败。
  3. 我们还有几个由spice 支持的quicksight 仪表板。这些 SPICE 数据集(约 6 个数据集)每 15 分钟刷新一次。

【问题讨论】:

    标签: database amazon-web-services amazon-redshift database-administration


    【解决方案1】:

    您需要两个带有写入的会话来创建序列化错误。因此,对于这个未描述的问题,还有更多重要的事情发生。仅刷新物化视图本身不会产生此问题。

    见:https://aws.amazon.com/premiumsupport/knowledge-center/redshift-serializable-isolation/

    在包含刷新的事务中还发生了什么?还有什么其他交易正在进行中,这是问题的另一半?如果这种情况反复发生,则可能有一些 ETL / 编排进程正在运行,以这样的方式启动两个事务,从而经常相互干扰。

    如果不清楚为什么会发生这种情况,您需要查看 MVCC - https://en.wikipedia.org/wiki/Multiversion_concurrency_control MVCC 允许在表上发生许多并行操作而不会相互阻塞。设置环境以创建序列化错误通常需要一些小心,而解决序列化问题通常只需要改变正在发生的事情的一小部分。但是,如果发生这种情况,则需要了解系统才能确定两个进程在干扰什么。

    【讨论】:

    • 嘿,这已经非常有帮助了。我添加了一些额外的上下文。您能否让我知道这对诊断问题是否有帮助。如果您还有其他问题,我可能还会添加更多信息。
    • 要获得序列化违规,您需要一个从 A 读取并写入 B 的事务以及另一个从 B 读取并写入 A 的事务。我看到物化视图从源表刷新其数据。但是某些 ETL 过程会根据物化视图更新这些表吗?
    • 有 4 个基表用于生成 mv A。然后还有第二个 mv 我将调用 b。有一些 ETL 进程不断地写入基表。 A 从 4 个基表读取并写入 A。B 从 A 读取并写入 B。但我认为没有任何东西可以完成这个循环。我已经看到 redshift 将我的刷新查询拆分为 3 个单独的查询作为优化,我认为这可能是它可能抱怨的,但我不确定
    • 它可以是 A 事务(不仅仅是更新查询)中创建对 B 的读取依赖项的任何内容。当您遇到序列化违规时,该错误应输出 2 个事务 ID (XID)。然后,您可以找到与这些事务关联的所有语句,以确切了解导致循环的原因(相关 XID 的 svl_statementext)。这 2 个 MV 更新是可能的,但回溯会消除猜测。然后你只需要序列化(在不同时间运行)这两个事务。
    【解决方案2】:

    当两个事务写入数据库,一个从被另一个修改的表中读取时,就会发生可序列化隔离违规。这种情况是described in detail here

    当用户事务中发生违规时,两个事务之一将中止并显示如下消息:

    表上的可序列化隔离违规 - 2342993,形成循环的事务是:104865204、104866208、104865323 (pid:20589);

    这提供了足够的信息来列出所涉及的每个事务的查询:

    SELECT * FROM svl_qlog WHERE xid IN (104865204, 104866208, 104865323) ORDER BY starttime;
    

    在无法刷新物化视图的情况下,您可能会发现 XID:

    SELECT * FROM SVL_MV_REFRESH_STATUS WHERE status LIKE '%violation%';
    

    这会给出您的表 ID。获取名称:

    SELECT * FROM pg_class WHERE oid = ...;
    

    然而,这只是故事的一方面。您缺少成功并干扰刷新的 XID。

    不幸的是,这有点侦探工作,我将从检查涉及表的查询开始:

    SELECT * FROM SVL_STATEMENTTEXT
    WHERE text LIKE '%your_table_name%'
      AND starttime > ... 
      AND endtime < ...
    

    祝你好运!

    【讨论】:

      猜你喜欢
      • 2020-01-31
      • 2014-04-29
      • 2018-04-20
      • 1970-01-01
      • 2018-04-11
      • 2018-08-23
      • 2021-10-14
      • 2014-07-11
      • 2017-11-13
      相关资源
      最近更新 更多