假设我有一个包含以下字段的简单表:
我从不使用ID字段进行查找,因为我的应用程序总是基于使用Name字段。
我需要不时更改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已更改,但对我的应用程序无关紧要。
答案 0 :(得分:60)
这个答案有点太迟了,但是由于我遇到了类似的问题,我在同一台机器上用JMeter和MySQL服务器进行了测试,我用过:
答案 1 :(得分:35)
表(列的数量和大小)越大,删除和插入而不是更新就越昂贵。因为你必须支付UNDO和REDO的价格。 DELETE比UPDATE消耗更多的UNDO空间,并且您的REDO包含两倍于必要的语句。
此外,从商业角度来看,这是完全错误的。考虑理解该表上的名义审计线索要困难得多。
有些情况涉及表中所有行的批量更新,其中使用旧表中的CTAS创建新表更快(在SELECT子句的投影中应用更新),删除旧表并重命名新表。副作用是创建索引,管理约束和更新权限,但值得考虑。
答案 2 :(得分:11)
同一行上的一个命令应始终比同一行上的两个命令快。所以UPDATE只会更好。
修改强> 设置表:
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
答案 3 :(得分:9)
我担心你的问题正文与标题问题无关。
如果要回答标题:
在SQL中,UPDATE总是快于DELETE + INSERT吗?
然后回答是NO!
只是谷歌
与直接插入+更新相比,此类更新通过插入+更新导致更高成本(更多处理)的更新实现。
时就是这种情况我的快速(非详尽)搜索,而不是假装覆盖一个,给了我[1],[2]
[1]
更新操作
(Sybase®SQLServer性能和调优指南
第7章:SQL Server查询优化器)
http://www.lcard.ru/~nail/sybase/perf/11500.htm
[2]
UPDATE语句可以复制为DELETE / INSERT对
http://support.microsoft.com/kb/238254
答案 4 :(得分:5)
刚尝试在包含44个字段的表上更新43个字段,其余字段是主要的群集密钥。
更新耗时8秒。
删除+插入比“客户端统计”通过SQL Management Studio报告的最小时间间隔快。
彼得
MS SQL 2008
答案 5 :(得分:4)
请记住,发出DELETE + INSERT时发生的实际碎片与正确实现的UPDATE相反会在时间上产生很大的差异。
这就是为什么,例如,不支持MySQL实现的REPLACE INTO,而不是使用INSERT INTO ... ON DUPLICATE KEY UPDATE ...语法。
答案 6 :(得分:4)
删除+插入几乎总是更快,因为更新涉及更多步骤。
更新
将新变量写入磁盘(整行)
(对于您正在更新的每一行重复此操作)
删除+插入:
使用新记录的位置更新PK索引。
(这不重复,所有这些都可以在一个操作块中执行)。
使用Insert + Delete会将文件系统分段,但速度不快。在后台进行延迟优化将总是释放未使用的块并完全打包表。
答案 7 :(得分:3)
在您的情况下,我相信更新会更快。
记住索引!
您已经定义了主键,它可能会自动成为聚簇索引(至少SQL Server会这样做)。集群索引表示根据索引将记录物理放置在磁盘上。 DELETE操作本身不会造成太大麻烦,即使一条记录消失后,索引保持正确。但是当您插入新记录时,数据库引擎必须将此记录放在正确的位置,在这种情况下会导致旧记录的某些“重新洗牌”为新记录“制造”。它会减慢操作的速度。
如果值不断增加,索引(尤其是群集)的效果最佳,因此新记录只会附加到尾部。也许你可以添加一个额外的INT IDENTITY列来成为聚簇索引,这将简化插入操作。
答案 8 :(得分:3)
如果你有几百万行怎么办?每行以一个数据开头,可能是客户名称。在为客户收集数据时,必须更新其条目。现在,让我们假设客户端数据的集合分布在许多其他机器上,稍后从中收集并放入数据库。如果每个客户端都有唯一的信息,那么您将无法执行批量更新;即,没有where子句标准供您一次更新多个客户端。另一方面,您可以执行批量插入。因此,问题可能更好地表现如下:执行数百万次单个更新是否更好,或者将它们编译为大型批量删除和插入更好。换句话说,代替“更新[表]设置字段=数据,其中clientid = 123”一个毫秒次,你做'从[表]删除clientid([所有客户端要更新]);插入[表]值(client1的数据),(client2的数据)等等
要么选择比另一个更好,要么两种方式都搞砸了?
答案 9 :(得分:2)
显然,答案因您使用的数据库而异,但UPDATE总是可以比DELETE + INSERT更快地实现。由于内存操作无论如何都是微不足道的,在给定基于硬盘驱动器的数据库的情况下,UPDATE可以在hdd上就地更改数据库字段,而删除则会删除一行(留空空格),并插入新的行,也许到表的末尾(再次,它都在实现中)。
另一个小问题是,当您在单行中更新单个变量时,该行中的其他列保持不变。如果删除然后执行INSERT,则存在忘记其他列并因此将其留下的风险(在这种情况下,您必须在DELETE之前执行SELECT以临时存储其他列,然后再使用INSERT将其写回)
答案 10 :(得分:2)
如果没有特定的速度问题,速度问题就无关紧要了。
如果您正在编写SQL代码以对现有行进行更改,则更新它。其他任何事情都是不正确的。
如果你要打破代码应该如何工作的规则,那么你最好有一个该死的好的,量化的理由,而不是一个模糊的想法“这种方式更快”,当你不要我知道什么是“更快”。
答案 11 :(得分:1)
这取决于产品。可以实现一种产品(在封面下)将所有UPDATE转换为(事务包装的)DELETE和INSERT。如果结果与UPDATE语义一致。
我不是说我知道有任何产品可以做到这一点,但它完全合法。
答案 12 :(得分:1)
每次写入数据库都有很多潜在的副作用。
删除:必须删除一行,更新索引,检查外键并可能级联删除等。 插入:必须分配一行 - 这可能代替已删除的行,可能不是;必须更新索引,检查外键等。 更新:必须更新一个或多个值;也许行的数据不再适合数据库的那个块,因此必须分配更多的空间,这可能会级联成重写的多个块,或者导致碎片块;如果值具有外键约束,则必须检查它们等等。
对于非常少量的列或者如果更新整行,则删除+插入可能会更快,但FK约束问题很大。当然,也许你现在没有FK约束,但这总是真的吗?如果你有一个触发器,如果更新操作真的是更新,则编写处理更新的代码会更容易。
需要考虑的另一个问题是,有时插入和删除会持有不同于更新的锁。在插入或删除时,DB可能会锁定整个表,而不是在更新该记录时锁定单个记录。
最后,如果您要更新记录,我建议您更新一条记录。然后检查数据库的性能统计信息和该表的统计信息,以查看是否有性能改进。其他任何事情都为时过早。
我工作的电子商务系统的一个例子:我们将信用卡交易数据存储在数据库中,分两步进行:首先,写一个部分交易来表明我们已经开始了这个过程。然后,当从银行更新授权数据时更新记录。我们可能已删除然后重新插入记录,但我们只是使用更新。我们的DBA告诉我们这个表是碎片化的,因为DB只为每一行分配了少量的空间,并且更新导致了块链接,因为它添加了大量数据。但是,我们只是将数据库调整为始终分配整行,而不是切换到DELETE + INSERT,这意味着更新可以使用预先分配的空白空间而没有任何问题。无需更改代码,代码仍然简单易懂。
答案 13 :(得分:0)
在特定情况下,删除+插入可以节省您的时间。我有一个有30000多行的表,并且每天使用数据文件更新/插入这些记录。上传过程生成95%的更新语句,因为记录已存在,5%的插入不存在。或者,将数据文件记录上载到临时表中,删除临时表中记录的目标表,然后从临时表中插入相同的表,已经显示出50%的时间增益。
答案 14 :(得分:0)
我的情况是大量的个人更新与批量删除/批量插入。我有过去几年中多个客户的历史销售数据。在获得验证数据之前(下个月的15日),我将每天调整销售数字以反映从其他来源获得的当前状态(这意味着每个客户每天最多覆盖45天的销售)。可能没有变化,或者可能有一些变化。我可以对逻辑进行编码以找到差异,然后更新/删除/插入受影响的记录,也可以只删除昨天的数字并插入今天的数字。显然,后一种方法更简单,但是如果由于流失而破坏表的性能,那么值得编写额外的逻辑来识别少数(或没有)已更改的记录,并且仅更新/删除/插入这些记录。
因此,我要替换记录,并且旧记录和新记录之间可能存在某些关系,但总的来说,我不一定要将旧数据与新数据进行匹配(多余的步骤,将导致删除,更新和插入)。此外,将更改的字段相对较少(最多20个字段中的7个或15个字段中的2个)。
可能会一起检索的记录将同时插入,因此它们在物理上应彼此靠近。这样是否可以弥补由于流失而造成的性能损失,并且比所有这些单独记录更新的撤消/重做成本要好吗?