在PostgreSQL中,我必须以小批量的方式获取id,并同时删除它们,这样就不会有两个客户端获取相同的id.

可惜的是,DELETE并不支持LIMIT,所以我提出了这个问题:

DELETE FROM codes
WHERE id IN (SELECT id FROM codes WHERE product = 'abc' LIMIT 100 FOR UPDATE)
RETURNING id

可悲的是,这是缓慢和串行算法(在某些情况下)—你不能SELECTDELETE运行,而不是 Select 相同的id两次.DELETE,直到你有SELECT个结果.

这导致性能不佳,当许多客户同时出现时.什么是我最好的 Select 来并行化/加速这一切?

PS:当产品与不同客户端不同时—数据库可以很好地并行化,但是当它们相同时—响应时间开始随着并行客户端请求的数量线性增长.

推荐答案

Assuming你不关心代码的消费顺序——在你的查询中没有ORDER BY表示.

使用SKIP LOCKED允许并行化.否则,多个并发调用定期堆积,等待前一个调用完成.

此外,在CTE中具体化您的 Select ,因为LIMIT子句与锁定子句不能很好地交互.参见:

WITH sel AS MATERIALIZED (
   SELECT id
   FROM   codes
   WHERE  product = 'abc'
   LIMIT  100
   FOR    UPDATE SKIP LOCKED
   )
DELETE FROM codes c
USING  sel s
WHERE  c.id = s.id
RETURNING c.id;

关键字MATERIALIZED不是严格需要的,因为这个CTE无论如何都不会被内联.但为了清楚起见不会有什么坏处.

现在,您可以同时安全地运行该命令的多个实例,每个实例都在一个单独的会话中.

要确保所有行都已处理完毕,请在您认为处理完毕后再判断.比如:

SELECT EXISTS (SELECT FROM codes WHERE product = 'abc');

如果仍有剩余行,则运行不含SKIP LOCKED的final命令.循环最后两个步骤,以确保绝对确定.或者只是循环命令而不使用SKIP LOCKED.

如果过滤器WHERE product = 'abc'实际上是 Select 性的,即,仅占总行的一小部分,则codes(product)上的索引应该会有所帮助.否则,它通常比帮助更多的成本,因为索引增加了写入成本.

Sql相关问答推荐

获取每个帖子的匹配关键字列表

SQL更新,在2个额外的表上使用内部连接

删除事务中的本地临时表

具有多个条件的SQL否定

在Netezza SQL中将字符DataType转换为整型DataType

如何在多列上编写具有不同条件的查询?

在 PostgreSQL 中生成时间序列查询

Athena 计算从日期到当前时间戳的每月计数

将 jsonb 数组中的对象取消嵌套到单独的行中

根据标识符将两行合并为一行

计算组内多个日期间隔go 年的累计天数

根据要过滤的列的值进行联接和分组

更新之前如何获得价值

在给定的日期范围内填写缺失的日期

将有效数字作为 varchar 返回的 SQL 函数

Set vs let vs 在snowflake中声明变量

使用 SAVE TRANSACTION 时 BEGIN 和 COMMIT 语句的数量不匹配

BigQuery 错误:SELECT 列表表达式引用 esthetician.LICENSE_TYPE,它既未在 [49:8] 分组也未聚合

使用一组值进行分组和计数

如何刷新在视图之上创建的表