如何在多线程环境中安全地插入/更新 Postgres 中的值
我在 PostgreSQL 中有一个如下所示的表,
create table item_counts {
item string,
view_count int}
我想使用该表来跟踪 item 的出现,并根据需要增加计数。最初表未填充,因此当第一次观察到新值时插入新值,否则 view_count 会增加。速度和多任务处理都是问题。
我知道我可以做
rows_affected = execute("update item_counts set view_count = view_count + 1
where item = ?")
if rows_affected == 0:
execute("insert into item_counts ...")
但是,这在多线程环境中是不安全的,所以我必须将其包装到事务中。这反过来会降低速度,因为每次插入/更新后都会发生提交。
有什么建议如何以干净有效的方式做到这一点?
I have a table in PostgreSQL that looks like this
create table item_counts {
item string,
view_count int}
I would like to use the table to keep track of occurrences of item, incrementing the counts as necessary. Initially the table is unpopulated, so a new value is inserted iff it is observed for the first time, otherwise the view_count is increased. Speed and multitasking are both concerns.
I know I can do
rows_affected = execute("update item_counts set view_count = view_count + 1
where item = ?")
if rows_affected == 0:
execute("insert into item_counts ...")
However, this is unsafe in a multithreaded environment, so I would have to wrap it into a transaction. This would in turn decrease the speed, since a commit would occur after each insert/update.
Any suggestions how to do it in a clean and efficient way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您使用的是 9.1,您可能会考虑可写 CTE:
http://vibhorkumar.wordpress.com/2011/10/26/upsertmerge-using-writable-cte-in-postgresql-9-1/
http://xzilla.net/blog/2011/Mar/Upserting-via-Writeable-CTE.html
If you are on 9.1, you might consider writeable CTEs:
http://vibhorkumar.wordpress.com/2011/10/26/upsertmerge-using-writable-cte-in-postgresql-9-1/
http://xzilla.net/blog/2011/Mar/Upserting-via-Writeable-CTE.html
或者,您可以在违反唯一异常时检查点、插入和更新(回滚检查点)。它是否更好值得怀疑,特别是如果您希望进行大部分更新。
此外,并发情况下的事务在提交时仍可能失败。
另外,您可以执行
insert
select
,插入表中没有的内容(使用 self-left-join 或 where not contains 子句,无论您喜欢什么),然后更新 if它产生 0 个受影响的行。也许,最好在服务器端的函数中执行此操作。
Alternatively, you can checkpoint,
insert
andupdate
on violating unique exception (rolling back the checkpoint). Whether it's better is doubtful, especially if you expect to by mostly-update.Also the transaction in case of concurrency may still fail at commit.
Also, you can do the
insert
select
, inserting what's NOT in the table (using self-left-join or where not exists clause, whatever pleases you) and then update if it yields 0 affected rows.And, perhaps, it's best if you do that in a function on the server side.