【问题标题】:Redshift: Serializable isolation violation on tableRedshift:表上的可序列化隔离违规
【发布时间】:2016-04-26 23:31:57
【问题描述】:

我有一个非常大的 Redshift 数据库,其中包含数十亿行 HTTP 请求数据。

我有一个名为requests 的表,其中包含一些重要字段:

  • ip_address
  • city
  • state
  • country

我有一个 Python 进程每天运行一次,它会抓取所有尚未进行地理编码的不同行(没有任何城市/州/国家信息),然后尝试通过 Google 的地理编码 API 对每个 IP 地址进行地理编码。

这个过程(伪代码)如下所示:

for ip_address in ips_to_geocode:
    country, state, city = geocode_ip_address(ip_address)
    execute_transaction('''
        UPDATE requests
        SET ip_country = %s, ip_state = %s, ip_city = %s
        WHERE ip_address = %s
    ''')

运行此代码时,我经常收到如下错误:

psycopg2.InternalError: 1023
DETAIL:  Serializable isolation violation on table - 108263, transactions forming the cycle are: 647671, 647682 (pid:23880)

我假设这是因为我有其他进程不断将 HTTP 请求记录到我的表中,所以当我尝试执行我的 UPDATE 语句时,它无法选择具有 ip 地址的 all 行我想更新。

我的问题是:我该怎么做才能以一种不会经常失败的理智方式更新这些记录?

【问题讨论】:

    标签: sql amazon-redshift


    【解决方案1】:

    您的代码违反了 Redshift 的可序列化隔离级别。在关闭所有打开的事务之前,您需要确保您的代码没有尝试在同一个表上打开多个事务。

    您可以通过在每个事务中锁定表来实现此目的,这样在打开的事务关闭之前,其他事务都无法访问表进行更新。不确定您的代码是如何构建的(同步或异步),但这会增加运行时间,因为每个锁都会迫使其他人等待事务结束。

    参考:http://docs.aws.amazon.com/redshift/latest/dg/r_LOCK.html

    【讨论】:

      【解决方案2】:

      您要么在对同一张表进行第二次更新时启动新会话,要么在事务完成后“提交”。

      您可以在开始更新之前编写 set autocommit=on。

      【讨论】:

        【解决方案3】:

        我的代码也遇到了同样的问题,这就是我修复它的方法:

        首先,很高兴知道这个错误代码意味着您正在尝试在 redshift 中执行并发操作。例如,当您在不久前执行的第一个查询完成之前对表执行第二个查询时,您会遇到这种错误(这是我的情况)。

        好消息是:有一种简单的方法可以序列化 redshift 操作!您只需要使用 LOCK 命令。这是redshift LOCK command 的亚马逊文档。它的工作原理基本上是使下一个操作等到​​前一个操作关闭。请注意,使用此命令,您的脚本自然会变慢一点。

        最后,对我来说实用的解决方案是:我在查询消息之前插入了 LOCK 命令(在同一个字符串中,用';'分隔)。像这样的:

        LOCK table_name; SELECT * from ...

        你应该很高兴!希望对你有帮助。

        【讨论】:

          【解决方案4】:

          由于您在地理代码更新过程中进行点更新,而其他进程正在写入表,您可以间歇性根据其他进程的方式和时间得到可序列化隔离违规错误进程写入同一个表。

          建议

          • 一种方法是使用Marcus Vinicius Melo 在他的回答中建议的表锁。
          • 另一种方法是捕获错误并重新运行事务。

          对于任何可序列化的事务,据说发起事务的代码应该准备好在面对这个错误时重试事务。由于 Redshift 中的所有事务都是严格可序列化的,因此在 Redshift 中启动事务的所有代码都应该准备好在遇到此错误时重试它们。

          说明

          此错误的典型原因是两个事务以这样一种方式开始并继续其操作,以至于其中至少一个事务无法完成,就好像它们一个接一个地执行一样。所以数据库系统选择通过抛出这个错误来中止其中一个。这实质上将控制权交还给事务启动代码,以采取适当的行动。重试成为其中之一。

          防止这种冲突的操作顺序的一种方法是使用锁。但是,它限制了许多情况的并发执行,这不会导致操作序列的冲突。锁将确保不会发生错误,但也会限制并发。重试方法让并发有机会并在发生冲突时处理这种情况。

          推荐

          也就是说,我仍然建议您不要以这种方式更新 Redshift,例如点更新。地理代码更新过程应写入临时表,并且在处理完所有记录后,执行一次批量更新,然后根据需要执行一次清理。

          【讨论】:

            猜你喜欢
            • 2021-02-08
            • 1970-01-01
            • 2019-05-21
            • 2015-07-27
            • 1970-01-01
            • 1970-01-01
            • 2018-02-05
            • 1970-01-01
            • 2020-07-16
            相关资源
            最近更新 更多