每次更新一行时运行10,000个查询会更快,或者每次更新100行会运行100个查询吗?

时间:2012-06-29 16:54:42

标签: mysql performance postgresql sql-update

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

-- 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个查询怎么样?

5 个答案:

答案 0 :(得分: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个语句放在一起并发送到服务器,这可能需要比UPDATE本身更长的时间。

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

  3. mytable.id上的索引是所有呈现的替代需求,其表现优于两个变体。

    CTE解析数组一次(子查询也可以工作 - MySQL没有CTE) - unnest()相当快。在一个语句中完成所有操作可以使10000个语句超过一个数量级。如果这些语句在单个事务中运行,则添加另一个数量级。如果您应该使用单独的会话,请添加另一个。

    罕见的例外适用于在 write 负载较重的情况下具有锁定问题的数据库。正如已建议的那样只是基准。 EXPLAIN ANALYZE是你在PostgreSQL中的朋友。

    如果操作增长 huge ,并且大部分表已更新和/或磁盘空间或内存不足,则可能仍然是个好主意将操作分成几个逻辑块 - 只是不是太多,找到最佳点。主要是让HOT updates回收之前UPDATE次运行的表膨胀。考虑this related question

答案 1 :(得分:4)

我发现第二种方法在为非常大的数据集进行插入时要快几个数量级。这非常依赖于您的系统,因为查询的IN部分或多或少会有效,具体取决于表大小,索引等。

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

答案 2 :(得分:3)

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

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

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

注意,几乎确定要慢一点,就是从客户端向数据库服务器运行10,000个语句。在存储过程中运行10,000个更新并从客户端运行10,000个更新是两个非常不同的事情。如果您要运行10,000次更新路线,请确保在SP中执行此操作。

答案 3 :(得分:2)

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

答案 4 :(得分:0)

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

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