更新声明的性能问题
Performance Concern for Update Statement
我的更新流程如下:
UPDATE Repairs
SET TypeID = CASE WHEN @TypeID IS NULL THEN TypeID ELSE @TypeID END,
Directions = CASE WHEN @Directions IS NULL THEN Directions ELSE @Directions END,
LastUpdate = SYSDATETIME()
WHERE RepairID = @RepairID
我没有并发问题,但 Directions
可能是一个很长的 NVarChar
字符串。 SQL 服务器是否足够智能,不会将现有数据复制到自身,还是我应该寻找其他方法?
这可以改写如下:
UPDATE Repairs
SET
TypeID = ISNULL(@TypeID, TypeID),
Directions = ISNULL(@Directions, Directions),
LastUpdate = SYSDATETIME()
WHERE RepairID = @RepairID;
但这不会产生任何显着差异。如果只是这几列,那么您可能有三种不同的情况来进行这些更新:
IF @TypeID IS NOT NULL
AND @Directions IS NOT NULL
UPDATE Repairs
SET
TypeID = ISNULL(@TypeID, TypeID),
Directions = ISNULL(@Directions, Directions),
LastUpdate = SYSDATETIME()
WHERE RepairID = @RepairID;
ELSE IF @TypeID IS NOT NULL
UPDATE Repairs
SET
TypeID = ISNULL(@TypeID, TypeID),
LastUpdate = SYSDATETIME()
WHERE RepairID = @RepairID;
ELSE IF @Directions IS NOT NULL
UPDATE Repairs
SET
Directions = ISNULL(@Directions, Directions),
LastUpdate = SYSDATETIME()
WHERE RepairID = @RepairID;
ELSE
THROW 51000, 'Nothing to update mate!', 1;
但我怀疑这是否也会产生重大影响。它只是为您的代码添加了太多样板。保持现有或 ISNULL()
s
Is SQL Server smart enough not to copy the existing data onto itself
Yes it is smart enough.
当您修改一行时,SQL 服务器仅记录修改后的字节,因此例如当您将 int 值从 1 更改为 24 时,SQL 服务器仅修改 4 ( int 值是 4 个字节长)
所做的更改可以以两种方式写入日志,如LOP_MODIFY_ROW
或LOP_MODIFY_COLUMNS
,但无论如何如果你的nvarchar值没有改变,只有行的固定长度部分会被记录(您更改的其他字段为定长类型)
如果您的字符串是 nchar(而不是 nVARchar),情况可能会有所不同,在这种情况下,table 定义中的列顺序很重要。
如果您没有修改 LastUpdate,则根本不会记录任何内容。
如果您的问题不是关于日志记录而是关于数据页,当然如果一行有任何更改(并且您总是至少修改 LastUpdate 字段),该页会立即被标记为脏页。这意味着此页面与存储在磁盘上的页面不同,下一个检查点操作会将其写入磁盘。
SQL 服务器并没有将每一个修改的行都写入磁盘,可以写入磁盘的最小数据量是一个页面(8Kb),但是并没有立即写入磁盘修改后,它是定期将脏页写入磁盘的检查点(好吧,或者是急切的写入器,或者准确地说是懒惰的写入器)。
我的更新流程如下:
UPDATE Repairs
SET TypeID = CASE WHEN @TypeID IS NULL THEN TypeID ELSE @TypeID END,
Directions = CASE WHEN @Directions IS NULL THEN Directions ELSE @Directions END,
LastUpdate = SYSDATETIME()
WHERE RepairID = @RepairID
我没有并发问题,但 Directions
可能是一个很长的 NVarChar
字符串。 SQL 服务器是否足够智能,不会将现有数据复制到自身,还是我应该寻找其他方法?
这可以改写如下:
UPDATE Repairs
SET
TypeID = ISNULL(@TypeID, TypeID),
Directions = ISNULL(@Directions, Directions),
LastUpdate = SYSDATETIME()
WHERE RepairID = @RepairID;
但这不会产生任何显着差异。如果只是这几列,那么您可能有三种不同的情况来进行这些更新:
IF @TypeID IS NOT NULL
AND @Directions IS NOT NULL
UPDATE Repairs
SET
TypeID = ISNULL(@TypeID, TypeID),
Directions = ISNULL(@Directions, Directions),
LastUpdate = SYSDATETIME()
WHERE RepairID = @RepairID;
ELSE IF @TypeID IS NOT NULL
UPDATE Repairs
SET
TypeID = ISNULL(@TypeID, TypeID),
LastUpdate = SYSDATETIME()
WHERE RepairID = @RepairID;
ELSE IF @Directions IS NOT NULL
UPDATE Repairs
SET
Directions = ISNULL(@Directions, Directions),
LastUpdate = SYSDATETIME()
WHERE RepairID = @RepairID;
ELSE
THROW 51000, 'Nothing to update mate!', 1;
但我怀疑这是否也会产生重大影响。它只是为您的代码添加了太多样板。保持现有或 ISNULL()
s
Is SQL Server smart enough not to copy the existing data onto itself Yes it is smart enough.
当您修改一行时,SQL 服务器仅记录修改后的字节,因此例如当您将 int 值从 1 更改为 24 时,SQL 服务器仅修改 4 ( int 值是 4 个字节长)
所做的更改可以以两种方式写入日志,如LOP_MODIFY_ROW
或LOP_MODIFY_COLUMNS
,但无论如何如果你的nvarchar值没有改变,只有行的固定长度部分会被记录(您更改的其他字段为定长类型)
如果您的字符串是 nchar(而不是 nVARchar),情况可能会有所不同,在这种情况下,table 定义中的列顺序很重要。
如果您没有修改 LastUpdate,则根本不会记录任何内容。
如果您的问题不是关于日志记录而是关于数据页,当然如果一行有任何更改(并且您总是至少修改 LastUpdate 字段),该页会立即被标记为脏页。这意味着此页面与存储在磁盘上的页面不同,下一个检查点操作会将其写入磁盘。
SQL 服务器并没有将每一个修改的行都写入磁盘,可以写入磁盘的最小数据量是一个页面(8Kb),但是并没有立即写入磁盘修改后,它是定期将脏页写入磁盘的检查点(好吧,或者是急切的写入器,或者准确地说是懒惰的写入器)。