3

假设我有一个主键列表,对于每一行,一个值需要更新。运行是否更好:

-- run 10,000 of these queries
UPDATE mytable SET myflag = 1 WHERE id = [each_id]

或者将更新组合成批处理查询,如下所示:

-- run 100 of these queries, where the IN () list contains about 100 elements
UPDATE mytable SET myflag = 1 WHERE id IN (3, 4, 5, 9, 99, ... 7887 )

有 100 个 IN () 项的 100 个查询怎么样?

4

5 回答 5

5

两者都不。在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 很多。问题中提出的两个想法要么:

  1. 必须解析列表并将 10000 条语句放在一起并将它们发送到服务器,这很可能比更新本身花费更长的时间。

  2. 必须在包含 10000 个项目的列表(数组)中为每个人id搜索mytable匹配的 ID。不能使用标准索引。这会很慢。性能随着 的大小而降低mytable

上的索引mytable.id是所有提出的替代方案都需要优于两个变体一个数量级。

CTE解析数组一次(子查询也有效 - MySQL 没有 CTE) - 并且unnest()速度相当快。在一个语句中完成所有操作比 10000 个语句高出一个数量级。如果这些语句在单个事务中运行,则再增加一个数量级。如果您应该使用单独的会话,请添加另一个。

罕见的例外适用于在繁重的写入负载下存在锁定问题的数据库。只是按照建议进行基准测试。EXPLAIN ANALYZE是你在 PostgreSQL 中的朋友。

如果操作变得庞大,并且大部分表都已更新和/或您的磁盘空间或 RAM 不足,则将操作拆分为几个逻辑块可能仍然是一个好主意 - 不要太多,找到最合适的点。主要是为了让HOT 更新UPDATE从以前的运行中回收表膨胀。考虑这个相关的问题

于 2012-06-29T18:36:09.013 回答
4

我发现第二种方法在对非常大的数据集进行插入时要快几个数量级。这在很大程度上取决于您的系统,但是因为查询的 IN 部分的效率或多或少取决于表大小、索引等。

做自己的简单基准测试确实是唯一的方法。

于 2012-06-29T17:01:40.563 回答
3

在正常情况下,运行一个更新语句是最有效的。例如,

UPDATE mytable set myflag=1 where id IN (select id from someothertable where stuff). 

根据您的架构,这可能会更慢您应该进行基准测试并找出答案。

请注意,几乎可以肯定的是,从客户端到数据库服务器运行 10,000 条语句会更慢。在存储过程中运行 10,000 次更新和从客户端运行 10,000 次更新是两个非常不同的事情。如果您要运行 10,000 次更新路线,请确保在 SP 中进行。

于 2012-06-29T17:01:03.507 回答
2

通常,RDBMS 往返是一个主要因素,但在这种情况下,解析in列表的成本也可能会很高。但是,如果您对查询进行参数化,则第二种解决方案很可能会更快,因为解析只会进行一次。

于 2012-06-29T17:00:03.830 回答
0

它主要取决于硬盘的 fsync 数量:这是系统中最慢的部分。

对于 PostgreSQL:在少量事务中进行,如果可能的话,只在一个事务中。但是要注意行锁定,两个事务不能同时更新同一行。

于 2012-06-29T16:59:56.967 回答