如何解决Upsert在冲突时与先读后写性能
每次登录的用户访问我的一个网页时,我都会在 (user_id,page_id) 表中添加一行以标记该页面已被访问,其中 (user_id,page_id) 是该表中的主键。 当然,如果用户再次访问此页面,则该行已经存在,因此无需添加新行。
我目前使用 postgres ON CONFLICT 子句首先尝试写入,如果有冲突,那么我什么都不做,因为该行已经存在。 但我担心,因为每次访问页面时都会发生这种写入操作,这会给数据库增加不必要的负载。
这种想法正确吗?如果是这样,那么不是在 CONFLICT DO NOTHING 上执行 upsert,而是应该做一个 READ 来检查表中是否已经存在这个 (user_id,page_id),如果没有,那么只执行插入?
upsert ON CONFLICT 的好处是它只是一个单一的数据库查询。第二种先读后写的方法是 2 次 DB 调用,这会变慢,因为它必须通过网络。但第一种方法的缺点是它在每次访问页面时都进行一次写入(或者它实际上不被认为是写入,因为它在 99% 的情况下会导致冲突?)。
我应该遵循哪种方式?
解决方法
您不需要单独的网络往返,您可以将其打包成一个语句。但是,在我手中,ON CONFLICT 比使用两列键的“预读”略快,并且不会产生额外的 IO。使用 pgbench 和自定义事务进行测试(一旦表被所有 1e6 行完全填充):
\set a random(1,1000)
\set b random(1,1000)
insert into foo (a,b) values (:a,:b) on conflict do nothing;
对比
\set a random(1,b) select :a,:b where not exists (select 1 from foo where a=:a and b=:b)
另外,预读可能会受到竞争条件的影响。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。