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

说我有一个简单的表,有以下字段:

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

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

我需要不时更改Tag值。 我正在使用以下琐碎的SQL代码:

UPDATE Table SET Tag = XX WHERE Name = YY; 

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

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

再次 – 我知道在第二个例子中,ID被改变,但是对于我的应用程序来说并不重要。

这个答案有点晚了,但是因为我遇到了类似的问题,所以我在同一台机器上用JMeter和一个MySQL服务器进行了testing:

  1. 包含两个JDBC请求的事务控制器(生成父示例):Delete和Insert语句
  2. 包含Update语句的sepparate JDBC Request。

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

DEL + INSERT – 平均:62ms

更新 – 平均:30ms

结果: 结果

表格(列的数量和大小)越大,删除和插入而不是更新就越昂贵。 因为你必须支付UNDO和REDO的价格。 删除比UPDATE消耗更多的UNDO空间,并且您的REDO包含必要的两倍的语句。

此外,从商业的angular度来看,这显然是错误的。 考虑在这张桌子上理解一个名义上的审计线索要困难得多。


有一些情况涉及表中所有行的批量更新,其中使用旧表(使用SELECT子句的投影中的更新)使用CTAS创build新表更快,删除旧表并重命名新表。 副作用是创build索引,pipe理约束和更新权限,但值得考虑。

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

编辑设置表格:

 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 

恐怕你的问题的主体与标题问题无关。

如果回答标题:

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

那么答案是否定的!

只是谷歌的

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

这样的更新通过插入+更新导致比直接插入+更新导致更高成本(更多处理)的更新实现。 这些是什么时候

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

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

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

只是试图用44个字段更新43个字段的表,其余的字段是主要的集群键。

更新花了8秒钟。

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

彼得

MS SQL 2008

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

更新:

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

    (这个重复你正在更新的每一行)

删除+插入:

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

    (这并不重复,所有操作都可以在一个操作块中完成)。

使用插入+删除会碎片你的文件系统,但不是那么快。 在后台进行一个懒惰的优化将总是释放未使用的块,并将表格打包。

请记住,发生DELETE + INSERT时发生的实际碎片与正确实施的UPDATE相反,会随时间而改变。

这就是为什么,例如,不要使用INSERT INTO … ON DUPLICATE KEY UPDATE …语法来替代MySQL实现的REPLACE INTO。

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

记住索引!

你已经定义了一个主键,它可能会自动成为一个聚集索引(至lessSQL Server是这样做的)。 簇索引意味着logging根据索引物理地放置在磁盘上。 DELETE操作本身不会造成太大麻烦,即使一条logging消失后,索引仍然是正确的。 但是,当你插入一条新logging时,数据库引擎将不得不将这个logging放在正确的位置,这样会导致旧logging“重新洗牌”,从而造成新的logging。 在那里它会放慢操作。

一个索引(特别是聚集的)如果值不断增加,效果最好,所以新的logging只是附加到尾部。 也许你可以添加一个额外的INT IDENTITY列成为一个聚集索引,这将简化插入操作。

如果你有几百万行呢? 每一行都以一个数据开始,也许是一个客户名称。 在为客户收集数据时,他们的条目必须更新。 现在,我们假设客户端数据的集合分布在许多其他机器上,以后再从这些机器收集并放入数据库。 如果每个客户都有独特的信息,那么您将无法执行批量更新; 即没有where-clause标准让你用一次更新多个客户端。 另一方面,您可以执行批量插入。 所以,这个问题可能会更好,如下所示:执行数百万次单个更新更好,还是将它们编译为大批量删除和插入更好? 换句话说,代替“更新[表]设置的字段=数据其中clientid = 123”一个微妙的时间,你可以从[table]中删除[[[所有待更新的客户端]);插入到[table]值(客户端1的数据),(客户端2的数据)等'

要么select比其他select更好,要么你是两种方式?

显然,答案根据你使用的数据库而不同,但是UPDATE总是可以比DELETE + INSERT更快地实现。 由于内存中的操作通常是微不足道的,给定一个基于硬盘的数据库,UPDATE可以在硬盘上就地更改数据库字段,而删除操作会删除一行(留下空白空间),并插入一个新的行,也许到表的末尾(再次,这一切都在实施中)。

另一个小问题是当你在一行中更新单个variables时,该行中的其他列保持不变。 如果DELETE,然后执行INSERT,则会冒着忘记其他列的风险,从而将其留在后面(在这种情况下,您必须在DELETE之前执行SELECT操作,临时存储其他列,然后再使用INSERT将其写回) 。

这取决于产品。 可以实现一个产品(在下面)将所有UPDATE转换成(事务封装的)DELETE和INSERT。 如果结果与UPDATE语义一致。

我不是说我知道有这样的产品,但是这是完全合法的。

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

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

对于非常less量的列或整行被更新删除+插入可能会更快,但FK约束问题是一个很大的问题。 当然,也许你现在没有FK限制,但是这样总会是真的吗? 如果你有一个触发器,如果​​更新操作是一个真正的更新,编写处理更新的代码将会更容易。

另一个要考虑的问题是有时插入和删除保持不同的锁而不是更新。 当您插入或删除数据库时,数据库可能会locking整个表格,而不是在更新该logging时locking单个logging。

最后,我build议只更新logging,如果你的意思是更新它。 然后检查您的数据库的性能统计信息和该表的统计信息,看看是否有性能改进。 还有什么是不成熟的。

我从事的电子商务系统的一个例子是:我们用两步法将信用卡交易数据存储在数据库中:首先编写一个部分交易来表明我们已经开始了这个过程。 然后,当授权数据从银行返回时更新logging。 我们可能已经删除,然后重新插入logging,而是我们只是使用更新。 我们的DBA告诉我们,表是碎片化的,因为数据库只为每行分配了less量的空间,并且更新引起了块链接,因为它添加了大量的数据。 但是,我们不是切换到DELETE + INSERT,而是调整数据库来始终分配整行,这意味着更新可以使用预先分配的空闲空间。 无需更改代码,代码仍然简单易懂。

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

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

如果你打算打破代码应该如何工作的规则,那么你最好有一个很好的,量化的原因,而不是一个“这样更快”的模糊的想法,当你没有想法“更快”是什么。

在特定的情况下,删除+插入会节省您的时间。 我有一个有30000奇数行的表,每天使用数据文件更新/插入这些logging。 上载过程生成95%的更新语句,因为logging已经存在,5%的插入不存在。 或者,将数据文件logging上载到临时表中,删除临时表中的logging的目的表,然后从临时表中插入相同的logging,已经显示出50%的时间增益。