如果相同的主键不存在,我正在尝试插入一行(在这种情况下忽略)。使用psycopg2和Postgres 9.3版从Python执行此操作。
有多种选择:1)使用subselect,2)使用事务,3)让它失败。
这样做似乎最简单:
try:
cursor.execute('INSERT...')
except psycopg2.IntegrityError:
pass
这种方法有什么缺点吗?失败会导致性能下降吗?
答案 0 :(得分:1)
目前这样做的简单方法是尝试插入并让它失败。你可以在应用程序级别或Postgres级别执行此操作;假设它不是服务器上正在执行的过程的一部分,那么当它涉及性能时它是一个或另一个并不重要,因为您向服务器发送请求并检索结果。 (如果您在交易中尝试保存点,则需要定义保存点,原因相同。或者,正如Craig的回答中所强调的那样,如果您有许多失败的陈述。)
在未来的版本中,正确的merge
和upsert
正在酝酿之中,但是近十年的长期讨论将建议正确实施它们是相当棘手的:
关于您提到的其他选项,上述维基页面及其中的链接应突出显示困难。基本上,如Erwin所述,使用subselect是便宜的,但不是并发证明(除非你正确锁定);使用锁定基本上等于锁定整个表(平凡但不是很好)或重新发明在核心中伪造的轮子(对于现有行来说是微不足道的,对于在寻求使用谓词而不是表格的情况下同时插入的潜在新轮子则更少)水平锁定);并且使用事务并捕获异常就是你最终会做的事情。
答案 1 :(得分:0)
正在努力为PostgreSQL 9.5 which will probably take the form of an INSERT ... ON CONFLICT UPDATE ...
statement添加本机upsert。
同时,您必须尝试更新,如果失败,请重试。虽然您可以loop within a PL/PgSQL function将其隐藏在应用程序中,但没有其他安全选择。
重新尝试并让它失败:
这种方法有什么缺点吗?
它会在日志文件中产生大量恼人的噪音。如果冲突率很高,它也会非常迅速地烧掉事务ID,可能需要更频繁地VACUUM FREEZE
由autovacuum运行,这可能是大型数据库的问题。
失败会导致性能下降吗?
如果冲突率很高,你将会进行一系列额外的数据库往返。否则不是很多。