只有当我传入存储过程的值与列中的值不同时,我才会更新列。它恰好是一个NVARCHAR(255)列,如果重要的话。
每次写这个值有什么利弊?如果我传入的内容与数据库中的内容不同,那么首先检查值并写入的优缺点是什么?
我在编写之前进行比较的简化示例:
-- @URL and @ContentName are parameters of the sproc
SET @ExistingURL =
(SELECT TOP 1 C.URL
FROM Content C
WHERE ContentName = @ContentName)
-- update only if the parameter and existing value are different
IF(@ExistingURL != @URL)
BEGIN
UPDATE Content
SET URL = @URL
WHERE ContentName = @ContentName
END
答案 0 :(得分:2)
您的查询似乎可以按如下方式重写,而无需将任何内容放入局部变量中。
UPDATE dbo.Content
SET URL = @URL
WHERE ContentName = @ContentName
AND URL <> @URL;
假设ContentName
是唯一的,这将影响0或1行。通过将URL的检查拉出到单独的查询中,不需要使逻辑更复杂。 “只在需要时写入”部分由WHERE
子句负责。
现在,如果您要将此扩展到多个列进行更新,那么您所追求的并不是那么简单(我认为这不值得)。例如,假设有另一个列名title
,并且您有一个名为@title
的变量。您预测仅在更改URL
时更新是明智的,并且仅在更改title
时更新。在理论上你可以通过几种方式实现这一点(并且请记住,这一切都假设变量和列都不可为空 - 如果它们是,它不会改变这些方法,只是使语法变得有点更令人生畏的):
运行两次独立更新
UPDATE dbo.Content SET URL = @URL
WHERE ... -- actual where clause
AND URL <> @URL;
UPDATE dbo.Content SET title = @title
WHERE ... -- same where clause
AND title <> @title;
有条件地更新
UPDATE dbo.Content
SET URL = CASE WHEN URL <> @URL THEN @URL ELSE URL END,
title = CASE WHEN title <> @title THEN @title ELSE title END
WHERE ... -- same where clause
AND (URL <> @URL OR title <> @title);
我怀疑后者不会比更自然的方式更好地执行此操作,因为无论如何你都要锁定并写入行(但除了代言之外,我没有任何可靠的证据证明来自迈克的上述评论):
UPDATE dbo.Content
SET URL = @URL, title = @title
WHERE ... -- same where clause
AND (URL <> @URL OR title <> @title);
换句话说,只需更新所有值,无论哪些值实际发生了变化。
答案 1 :(得分:1)
名义上写入的时间是读取的两倍 写入将锁定,因此它可能会阻止读取 它会在交易日志中输入一个条目 如果您触发该值,该怎么办?
作为一种惯例,我测试&lt;&gt;在任何活动数据库上。
如果桌子处于活动状态,对每一行进行锁定可能会受到重创 您的更新必须获取锁 其他查询必须等待你的锁(除非他们接受脏读)。
如果你只是实际更新了一个大型活动表上的10%的行,并且通过不测试&lt;&gt;而盲目更新所有行那是一个很大的打击。
如果你要更新99%的行,那么你会受到轻微的打击 测试&lt;&gt;需要时间。
通过检查你可能会受到轻微打击,但不检查你(和其他人)可能会受到重创。
检查&lt;&gt;
的更新示例Update [docSVsys] set [ftsStatus] = 5 where [ftsStaus] <> 5
锁定在整行上 - 而不是单个列。 如果您要更新超过1个值,那么仍然重要的是行数百分比。
Update [docSVsys] set [ftsStatus] = 5, [wfID] = 3
where [ftsStatus] <> 5 or [wfID] <> 3
如果只更改其中一个值,则更新两者都不是命中,因为它必须获取行上的更新锁定。
多个小时后发布的实际声明。
正如亚伦所说,左联盟什么都不做。
因为第一个查询返回@URL或null 它不是基于ContentName。
所以看着
if(@ExistingURL != @URL)
只有表中没有行具有该值时才会出现这种情况。
唯一约束不会与只允许一个null相同。
我很惊讶你的问题不是。此更新失败了吗?
答案 2 :(得分:1)
有一个简单的模式可以解决这个问题:
update my_table set
my_col = 'newValue'
where id = 'someKey'
and my_col != 'newValue';
如果值不需要更新,则此查询具有索引读取的性能,并且重要的是不锁定任何行。
只有当值需要更新时,where子句会触及一行并将其锁定(尽管是暂时的)以进行更新。
您可以使用相同的逻辑对此进行扩展以处理多个列:
update my_table set
my_col1 = 'newValue1',
my_col2 = 'newValue2'
where id = 'someKey'
and (my_col1 != 'newValue1'
or my_col2 != 'newValue2');