82

假设我有一个包含以下字段的简单表:

  1. ID: int, autoincremental (identity), 主键
  2. 名称:varchar(50),唯一,具有唯一索引
  3. 标签: int

我从不使用 ID 字段进行查找,因为我的应用程序始终基于使用 Name 字段。

我需要不时更改标签值。我正在使用以下简单的 SQL 代码:

UPDATE Table SET Tag = XX WHERE Name = YY;

我想知道是否有人知道上述是否总是比:

DELETE FROM Table WHERE Name = YY;
INSERT INTO Table (Name, Tag) VALUES (YY, XX);

再次 - 我知道在第二个示例中 ID 已更改,但这对我的应用程序无关紧要。

4

15 回答 15

88

这个答案有点太晚了,但是由于我遇到了类似的问题,所以我在同一台机器上使用 JMeter 和 MySQL 服务器进行了测试,我使用过:

  1. 包含两个 JDBC 请求的事务控制器(生成父样本):删除和插入语句
  2. 包含更新语句的单独 JDBC 请求。

在运行 500 次循环后,我得到了以下结果:

DEL + INSERT - 平均:62ms

更新 - 平均:30 毫秒

结果: 结果

于 2015-03-19T09:52:23.600 回答
49

表越大(列的数量和大小),删除和插入而不是更新的成本就越高。因为你要付出UNDO和REDO的代价。DELETE 比 UPDATE 占用更多的 UNDO 空间,并且您的 REDO 包含的语句数量是必要的两倍。

此外,从商业角度来看,这是完全错误的。考虑一下要理解该表上的名义审计跟踪会有多困难。


有些场景涉及批量更新表中的所有行,使用旧表中的 CTAS 创建新表(在 SELECT 子句的投影中应用更新)、删除旧表并重命名新表。副作用是创建索引、管理约束和更新权限,但值得考虑。

于 2009-08-13T13:15:27.643 回答
14

同一行上的一个命令应该总是比同一行上的两个命令快。所以只更新会更好。

编辑 设置表:

create table YourTable
(YourName  varchar(50)  primary key
,Tag int
)

insert into YourTable values ('first value',1)

运行这个,在我的系统(sql server 2005)上需要 1 秒:

SET NOCOUNT ON
declare @x int
declare @y int
select @x=0,@y=0
UPDATE YourTable set YourName='new name'
while @x<10000
begin
    Set @x=@x+1
    update YourTable set YourName='new name' where YourName='new name'
    SET @y=@y+@@ROWCOUNT
end
print @y

运行这个,在我的系统上花了 2 秒钟:

SET NOCOUNT ON
declare @x int
declare @y int
select @x=0,@y=0
while @x<10000
begin
    Set @x=@x+1
    DELETE YourTable WHERE YourName='new name'
    insert into YourTable values ('new name',1)
    SET @y=@y+@@ROWCOUNT
end
print @y
于 2009-08-13T12:31:46.570 回答
10

恐怕您的问题与标题问题无关。

如果回答标题:

在 SQL 中,UPDATE 总是比 DELETE+INSERT 快吗?

那么答案是否定的!

只是谷歌

  • “昂贵的直接更新”*“sql server”
  • “延迟更新”* “sql 服务器”

与直接插入+更新相比,此类更新导致通过插入+更新实现更新的成本更高(更多处理)。这些是当

  • 使用唯一(或主)键更新字段或
  • 当新数据不适合(更大)分配的更新前行空间(甚至最大行大小),导致碎片,
  • 等等

我的快速(非详尽)搜索,不假装覆盖一个,给了我 [1],[2]

[1]
更新操作
(Sybase® SQL Server 性能和调优指南
第 7 章:SQL Server 查询优化器)
http://www.lcard.ru/~nail/sybase/perf/11500.htm
[2]
UPDATE 语句可能是复制为 DELETE/INSERT Pairs
http://support.microsoft.com/kb/238254

于 2010-10-09T17:26:04.543 回答
5

请记住,当 DELETE+INSERT 与正确实施的 UPDATE 相反时发生的实际碎片会随着时间的推移而产生很大的差异。

这就是为什么不鼓励使用 MySQL 实现的 REPLACE INTO 而不是使用 INSERT INTO ... ON DUPLICATE KEY UPDATE ... 语法的原因。

于 2009-08-13T12:42:59.533 回答
5

刚刚尝试更新具有 44 个字段的表上的 43 个字段,其余字段是主聚集键。

更新耗时 8 秒。

Delete + Insert 比“Client Statistics”通过 SQL Management Studio 报告的最小时间间隔更快。

彼得

微软 SQL 2008

于 2009-08-27T10:46:53.373 回答
4

在你的情况下,我相信更新会更快。

记住索引!

您已经定义了一个主键,它很可能会自动成为一个聚集索引(至少 SQL Server 是这样做的)。集群索引意味着记录根据索引物理放置在磁盘上。DELETE 操作本身不会造成太大的麻烦,即使在一条记录消失后,索引仍然保持正确。但是当您插入一条新记录时,数据库引擎将不得不将此记录放在正确的位置,这在某些情况下会导致旧记录的一些“重新洗牌”为新记录“腾出位置”。在那里它会减慢操作速度。

如果值不断增加,则索引(尤其是集群)效果最好,因此新记录只会附加到尾部。也许您可以添加一个额外的 INT IDENTITY 列成为聚集索引,这将简化插入操作。

于 2009-08-13T12:47:18.380 回答
4

What if you have a few million rows. Each row starts with one piece of data, perhaps a client name. As you collect data for clients, their entries must be updated. Now, let's assume that the collection of client data is distributed across numerous other machines from which it is later collected and put into the database. If each client has unique information, then you would not be able to perform a bulk update; i.e., there is no where-clause criteria for you to use to update multiple clients in one shot. On the other hand, you could perform bulk inserts. So, the question might be better posed as follows: Is it better to perform millions of single updates, or is it better to compile them into large bulk deletes and inserts. In other words, instead of "update [table] set field=data where clientid=123" a milltion times, you do 'delete from [table] where clientid in ([all clients to be updated]);insert into [table] values (data for client1), (data for client2), etc'

Is either choice better than the other, or are you screwed both ways?

于 2011-01-10T12:04:03.807 回答
4

如果没有特定的速度问题,速度问题是无关紧要的。

如果您正在编写 SQL 代码来更改现有行,请更新它。其他任何事情都不正确。

如果你要打破代码应该如何工作的规则,那么你最好有一个该死的好,量化的理由,而不是“这种方式更快”的模糊想法,当你没有任何知道什么是“更快”。

于 2010-10-10T03:07:53.943 回答
2

显然,答案因您使用的数据库而异,但 UPDATE 总是可以比 DELETE+INSERT 更快地实现。由于内存中的操作无论如何都是微不足道的,给定一个基于硬盘驱动器的数据库,更新可以在硬盘上就地更改数据库字段,而删除将删除一行(留下一个空白空间),并插入一个新的行,也许到表的末尾(同样,这一切都在实现中)。

另一个较小的问题是,当您更新单行中的单个变量时,该行中的其他列保持不变。如果您 DELETE 然后执行 INSERT,则可能会忘记其他列并因此留下它们(在这种情况下,您必须在 DELETE 之前执行 SELECT 以临时存储其他列,然后再使用 INSERT 将它们写回) .

于 2009-08-13T12:38:12.430 回答
2

删除 + 插入几乎总是更快,因为更新涉及更多步骤。

更新:

  1. 使用 PK 查找行。
  2. 从磁盘读取行。
  3. 检查哪些值已更改
  4. 使用填充的 :NEW 和 :OLD 变量引发 onUpdate 触发器
  5. 将新变量写入磁盘(整行)

    (这对您要更新的每一行重复)

删除+插入:

  1. 将行标记为已删除(仅在 PK 中)。
  2. 在表格末尾插入新行。
  3. 使用新记录的位置更新 PK 索引。

    (这里不再重复,所有操作都可以在单个操作块中执行)。

使用 Insert + Delete 会分散您的文件系统,但不会那么快。在后台进行惰性优化将始终释放未使用的块并完全打包表。

于 2012-12-05T18:32:46.703 回答
1

在特定情况下,删除+插入可以节省您的时间。我有一个包含 30000 奇数行的表,并且使用数据文件每天更新​​/插入这些记录。上传过程生成 95% 的更新语句,因为记录已经存在,5% 的插入语句用于不存在的记录。或者,将数据文件记录上传到临时表中,删除临时表中记录的目标表,然后从临时表中插入相同的记录,这样可以节省 50% 的时间。

于 2012-02-22T10:58:55.333 回答
1

每次写入数据库都有很多潜在的副作用。

删除:必须删除一行,更新索引,检查外键并可能级联删除等。插入:必须分配一行 - 这可能代替删除的行,可能不是;必须更新索引,检查外键等。 更新:必须更新一个或多个值;也许该行的数据不再适合数据库的该块,因此必须分配更多空间,这可能会级联成多个正在重写的块,或导致碎片块;如果该值具有外键约束,则必须对其进行检查等。

对于极少数列或整行更新,Delete+insert 可能会更快,但 FK 约束问题是一个大问题。当然,也许您现在没有 FK 限制,但这是否总是正确的?如果你有一个触发器,如果​​更新操作确实是一个更新,那么编写处理更新的代码会更容易。

另一个需要考虑的问题是,有时插入和删除所持有的锁与更新所持有的锁不同。数据库可能会在您插入或删除时锁定整个表,而不是在您更新该记录时锁定单个记录。

最后,如果您要更新记录,我建议您只更新记录。然后检查数据库的性能统计信息和该表的统计信息,看看是否有性能改进。其他任何事情都为时过早。

我工作的电子商务系统的一个示例:我们以两步方法将信用卡交易数据存储在数据库中:首先,编写部分交易以表明我们已经开始了该过程。然后,当授权数据从银行返回时更新记录。我们可以删除然后重新插入记录,但我们只是使用更新。我们的 DBA 告诉我们,表是碎片化的,因为 DB 只为每一行分配少量空间,并且更新导致了块链,因为它添加了很多数据。但是,我们没有切换到 DELETE+INSERT,而是将数据库调整为始终分配整行,这意味着更新可以毫无问题地使用预先分配的空白空间。无需更改代码,代码保持简单易懂。

于 2009-08-13T14:31:05.610 回答
1

这取决于产品。可以实现一个产品,它(在幕后)将所有 UPDATE 转换为(事务性包装的)DELETE 和 INSERT。如果结果与 UPDATE 语义一致。

我并不是说我知道有任何产品可以做到这一点,但这是完全合法的。

于 2009-08-13T13:10:29.753 回答
1

大量的个人更新与批量删除/批量插入是我的场景。我有多个客户的历史销售数据可以追溯到几年前。在我获得验证数据(下个月 15 日)之前,我将每天调整销售数字以反映从另一个来源获得的当前状态(这意味着每个客户每天最多覆盖 45 天的销售)。可能没有变化,也可能有一些变化。我可以编写逻辑代码以查找差异并更新/删除/插入受影响的记录,或者我可以删除昨天的数字并插入今天的数字。显然,后一种方法更简单,但如果它会因为流失而扼杀表的性能,那么它

所以,我正在替换记录,旧记录和新记录之间可能存在某种关系,但总的来说,我不一定想将旧数据与新数据匹配(这将是一个额外的步骤和将导致删除、更新和插入)。此外,将更改的字段相对较少(最多 20 个字段中的 7 个或 15 个字段中的 2 个)。

可能一起检索的记录将同时插入,因此物理上应该彼此靠近。这是否弥补了由于这种方法的流失而造成的性能损失,它是否比所有这些单独记录更新的撤消/重做成本更好?

于 2020-01-03T14:42:36.437 回答