Sql server Update语句的性能问题
我有如下更新程序:Sql server Update语句的性能问题,sql-server,sql-update,query-performance,Sql Server,Sql Update,Query Performance,我有如下更新程序: 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 UPDATE Repai
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
UPDATE Repairs
SET
TypeID = ISNULL(@TypeID, TypeID),
Directions = ISNULL(@Directions, Directions),
LastUpdate = SYSDATETIME()
WHERE RepairID = @RepairID;
我没有并发问题,但是
Directions
可能是一个相当长的NVarChar
字符串。SQL Server是否足够聪明,不会将现有数据复制到自身,或者我是否应该寻找另一种方法?这可以重写如下:
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
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这可以重写如下:
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
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
SQL Server是否足够聪明,不会将现有数据复制到自身
是的,它足够聪明
修改行时,SQL Server只记录修改过的字节,因此,例如,当您将int值从1更改为24时,SQL Server只修改1个字节(int值为4字节长)
所做的更改可以通过两种方式写入日志,即LOP\u MODIFY\u ROW
或LOP\u MODIFY\u COLUMNS
,但无论如何,如果您的nvarchar值没有更改,则只会记录行的固定长度部分(您更改的其他字段属于固定长度类型)
如果字符串是nchar(而不是nVARchar),则可能会有所不同,在这种情况下,表定义中的列顺序很重要
若你们并没有修改LastUpdate,那个么根本就并没有日志记录
如果您的问题不是关于日志记录,而是关于数据页,当然,如果行有任何更改(并且您始终至少修改LastUpdate字段),则该页将立即标记为脏页。这意味着此页面与存储在磁盘上的页面不同,下一个checkpoin操作将把它写入磁盘
SQL Server并没有将每一个修改的行写入磁盘,可以写入磁盘的最小数据量是一页(8Kb),但它不会在修改后立即写入磁盘,而是定期将脏页写入磁盘的检查点(ok,或者确切地说是热切写入器,或者是懒惰写入器)
SQL Server是否足够聪明,不会将现有数据复制到自身
是的,它足够聪明
修改行时,SQL Server只记录修改过的字节,因此,例如,当您将int值从1更改为24时,SQL Server只修改1个字节(int值为4字节长)
所做的更改可以通过两种方式写入日志,即LOP\u MODIFY\u ROW
或LOP\u MODIFY\u COLUMNS
,但无论如何,如果您的nvarchar值没有更改,则只会记录行的固定长度部分(您更改的其他字段属于固定长度类型)
如果字符串是nchar(而不是nVARchar),则可能会有所不同,在这种情况下,表定义中的列顺序很重要
若你们并没有修改LastUpdate,那个么根本就并没有日志记录
如果您的问题不是关于日志记录,而是关于数据页,当然,如果行有任何更改(并且您始终至少修改LastUpdate字段),则该页将立即标记为脏页。这意味着此页面与存储在磁盘上的页面不同,下一个checkpoin操作将把它写入磁盘
SQL Server并没有将所有修改的行写入磁盘,可以写入磁盘的最小数据量为一页(8Kb),但它并不是在修改后立即写入磁盘,而是检查点(准确地说,是“ok”,或“急切写入器”,或“惰性写入器”)定期将脏页写入磁盘。即使没有任何更改,您是否希望更新最后一个更新列?我觉得这是一个过早的优化。您是否已经对此进行了测试和测量,并确定存在性能问题?@MartinSmith这是在一个存储过程中,除非至少有一个输入变量不为null,否则将不会调用该存储过程。是否希望即使没有任何更改,也能更新最后一个更新列?我觉得这是一个过早的优化。您是否已经对其进行了测试和测量,并确定存在性能问题?@MartinSmith这是一个存储过程,除非至少有一个输入变量不为null,否则不会调用该存储过程。不,我不关心日志记录。您回复的第二部分是我一直在寻找的,因此我将此标记为答案。好的,尽管我建议考虑日志记录,因为这可能是性能问题:更新始终是一个完全记录的操作,这意味着在提交之前,日志缓冲区会写入磁盘,并且是一个I\O操作。所以,当您在1000个事务中更新1000行时,将至少有1000个日志写入磁盘,而根本无法写入数据文件。不,我不关心日志记录。您回复的第二部分是我一直在寻找的,因此我将此标记为答案。好的,尽管我建议考虑日志记录,因为这可能是性能问题:更新始终是一个完全记录的操作,这意味着在提交之前,日志缓冲区会写入磁盘,并且是一个I\O操作。因此,当您在1000个事务中更新1000行时,将至少有1000个日志写入磁盘,而在allI上则无法写入数据文件。我没有想过使用更简单的样式来检查空值。我并不声称自己有很多SQL代码,所以这很有帮助。我没有想过使用更简单的样式来检查空值。我并不声称自己有很多SQL排版,所以这是有帮助的。