Redshift:表

时间:2016-01-20 22:08:44

标签: sql amazon-redshift

我有一个非常大的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地址的所有行我想更新。

我的问题是:如何以理智的方式更新这些记录,以便定期停止失败?

4 个答案:

答案 0 :(得分:5)

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

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

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

答案 1 :(得分:3)

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

首先,最好知道这个错误代码意味着你试图在redshift中进行并发操作。当您在第一个查询之前对表执行第二次查询时,您刚刚完成了,例如,您将遇到此类错误(这是我的情况)。

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

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

LOCK table_name; SELECT * from ...

你应该好好去!我希望它可以帮助你。

答案 2 :(得分:0)

当您在同一张桌子上进行第二次更新时,您可以开始新的会话,或者您必须提交'交易完成后。

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

答案 3 :(得分:0)

由于在地理代码更新过程中正在进行点更新,而其他过程正在向表写入数据,因此您可以间歇性间歇性地获得“可序列化隔离违规”错误,具体取决于其他方式和时间进程将其写入同一张表。

建议

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

对于任何可序列化的交易,据说面对该错误,启动交易的代码应准备重试该交易。由于Redshift中的所有事务都是严格可序列化的,因此面对此错误,Redshift中的所有代码启动事务都应准备重试。

说明

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

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

推荐

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