ani*_*ion 6 performance sql-server transaction
我们在后端使用SqlTransaction类来访问存储在 MS-SQLServer 中的数据。
在某些情况下,我们肯定知道此事务没有更改任何数据(并且没有发生错误)。所以问题是:在这些情况下如何关闭交易?我们应该使用Commit()
or Rollback()
,还是不使用这两个功能或其他功能?目的是找到最高效的方式以“合理”的方式完成交易。
AMt*_*two 14
反过来想想。仅ROLLBACK
当您有理由撤消自事务开始以来的所有内容时才发出 a - 例如异常、错误状态或明确希望撤消所有内容。如果一切都按计划进行,那么您应该始终COMMIT
。
发出 aROLLBACK
将导致 SQL Server 撤消在事务内执行的任何工作。
即使您“知道”SQL Server 没有更改数据,发出 a 确实没有任何好处,ROLLBACK
除非您希望 SQL Server 撤消更改,因为您担心无意的更改。如果您 100% 确定没有任何变化,那么我可以 100% 有信心说您应该只发出一个COMMIT
。
如果您的代码进行了技术上更新但逻辑上没有更改的更改,那么ROLLBACK
将是额外的工作。
首先,让我们创建一个新鲜、干净和原始的新数据库。它像新床单一样干净清新:
CREATE DATABASE RollMeBack;
ALTER DATABASE RollMeBack SET RECOVERY SIMPLE;
USE RollMeBack
GO
--Create a table
CREATE TABLE dbo.WidgetQueue (
QueueID bigint identity(1,1),
QueueStatus char(1),
SomeOtherStuff varchar(500)
CONSTRAINT PK_WidgetQueue PRIMARY KEY CLUSTERED (QueueID)
);
GO
--put some stuff in it
INSERT INTO dbo.WidgetQueue (QueueStatus, SomeOtherStuff)
SELECT QueueStatus = CASE c2. column_id%3
WHEN 0 THEN 'Q'
WHEN 1 THEN 'S'
WHEN 2 THEN 'L'
END,
SomeOtherStuff = c1.name + c2.name
FROM sys.columns AS c1
CROSS JOIN sys.columns AS c2;
GO 5
CHECKPOINT;
BACKUP DATABASE RollMeBack TO DISK = 'NUL;';
Run Code Online (Sandbox Code Playgroud)
那将是一张漂亮的大桌子。它可能不需要那么大。现在,让我们重新CHECKPOINT
审视一下事务日志。我得到 3 行返回。他们说什么并不重要,现在这并不重要。
USE RollMeBack
GO
CHECKPOINT;
SELECT *
FROM sys.fn_dblog(NULL,NULL);
Run Code Online (Sandbox Code Playgroud)
现在,我们将在事务中进行更新,逻辑上不会进行任何更改,但实际上会更新一堆行。对我来说,这会在 2 秒内运行,并更新 1892100 行,将状态设置为与当前值完全相同的值。
BEGIN TRANSACTION
UPDATE q
SET QueueStatus = 'S'
FROM dbo.WidgetQueue AS q
WHERE QueueStatus = 'S';
Run Code Online (Sandbox Code Playgroud)
现在,让我们再次查看事务日志:
SELECT *
FROM sys.fn_dblog(NULL,NULL);
Run Code Online (Sandbox Code Playgroud)
对我来说,这会返回 2916 行——这些是 2916 条记录事务日志中的事务的日志记录。你的旅费可能会改变。这些日志记录基本上是衡量 SQL Server 在您的事务期间所做的事情。所有这些日志记录都告诉我们 SQL Server 在该事务中做了大量工作。从逻辑上讲,它的净结果为零,并且数据看起来与开始时完全相同......除了 SQL Server 实际更新了这些行。
如果我ROLLBACK
现在发出 a ,SQL Server 将撤消这些更新。从逻辑上讲,这与不理会他们是一样的结果,但 SQL Server 只是按照它的指示去做,它必须通过那些 2916 条日志记录来解开它所做的事情,并确保它让一切都保持原样在交易开始时。
如果我COMMIT
改为发出 a ,SQL Server 只会说“OK。DONE!” 并记录,COMMIT
而无需解开已完成的工作。
在我们开始之前,让我们删除我们创建的用于测试的数据库。
USE master
GO
DROP DATABASE RollMeBack;
Run Code Online (Sandbox Code Playgroud)
如果我的dbo.QueueStatus
桌子上有触发器怎么办?然后我的更新可能会引发一些我没有意识到但仍然很重要的其他工作。
您还让开发人员有责任了解、理解和维护在该事务中完成的工作为零的事实。对应用程序的未来更改可能会引入导致更改的代码路径——现在需要更新应用程序逻辑以知道不要回滚。
日志呢?即使只是在开发周期中临时记录将一些内容放入日志表以尝试解决问题,该记录也会回滚。