两者都不。在PostgreSQL中,我会改为:
WITH x AS (
SELECT unnest('{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40
,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60
,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80
,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100
}'::int[]) AS id
)
UPDATE mytable t
SET myflag = 1
FROM x
WHERE t.id = x.id;
我在我的示例中放置了这么多 ID,以提供一个直观的线索,即 10000 个 ID 很多。问题中提出的两个想法要么:
必须解析列表并将 10000 条语句放在一起并将它们发送到服务器,这很可能比更新本身花费更长的时间。
必须在包含 10000 个项目的列表(数组)中为每个人id
搜索mytable
匹配的 ID。不能使用标准索引。这会很慢。性能随着 的大小而降低mytable
。
上的索引mytable.id
是所有提出的替代方案都需要优于两个变体一个数量级。
CTE解析数组一次(子查询也有效 - MySQL 没有 CTE) - 并且unnest()
速度相当快。在一个语句中完成所有操作比 10000 个语句高出一个数量级。如果这些语句在单个事务中运行,则再增加一个数量级。如果您应该使用单独的会话,请添加另一个。
罕见的例外适用于在繁重的写入负载下存在锁定问题的数据库。只是按照建议进行基准测试。EXPLAIN ANALYZE
是你在 PostgreSQL 中的朋友。
如果操作变得庞大,并且大部分表都已更新和/或您的磁盘空间或 RAM 不足,则将操作拆分为几个逻辑块可能仍然是一个好主意 - 不要太多,找到最合适的点。主要是为了让HOT 更新UPDATE
从以前的运行中回收表膨胀。考虑这个相关的问题。