如何解决事务块会降低SQL Server的性能吗?
| 现在,我和一个同事正在争论非重要的BEGIN TRAN ... COMMIT TRAN块的影响。 我已经为简单的插入-更新-删除操作编写了约140个存储过程,由于以后我们可能需要在其中进行一些额外的操作,因此我已经包括了可能必要的BEGIN TRAN和COMMIT TRAN块,所以:CREATE PROCEDURE [Users].[Login_Insert]
@Username nvarchar (50) OUTPUT,@Password char (40),@FullName nvarchar (150),@LoginTypeId int
AS
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRAN
INSERT [Users].[Login]
(
[Username],[Password],[FullName],[LoginTypeId]
)
VALUES
(
@Username,@Password,@FullName,@LoginTypeId
)
COMMIT TRAN
RETURN 1
END TRY
BEGIN CATCH
ROLLBACK TRAN
RETURN -1
END CATCH
GO
现在,其中许多交易可能不再需要。这些多余的块会以明显的方式影响性能吗?
提前致谢。
解决方法
还不足以引起注意。
也就是说,每个TXN将在BEGIN TRAN和INSERT之间打开一个额外的OhNoSecond。如果有人可以衡量我,我会印象深刻。
但是,如果您进行了BEGIN TRAN,然后提示用户输入,则您的腿需要折断...
不过好主意:我这样做是为了使我所有的写过程都是100%一致的,具有相同的错误处理,可以嵌套等
编辑:在Remus回答之后,我看到我没有链接到我的嵌套TXN模板:包含TRY CATCH ROLLBACK模式的嵌套存储过程?这与Remus \'的不同之处在于,它总是回滚并且没有SAVEPOINTs
编辑,一个快速而肮脏的测试显示它在进行交易时的速度大约是2/3
SET NOCOUNT ON
SET STATISTICS IO OFF
DECLARE @date DATETIME2
DECLARE @noTran INT
DECLARE @withTran INT
SET @noTran = 0
SET @withTran = 0
DECLARE @t TABLE (ColA INT)
INSERT @t VALUES (1)
DECLARE
@count INT,@value INT
SET @count = 1
WHILE @count < 100
BEGIN
SET @date = GETDATE()
UPDATE smalltable SET smalltablename = CASE smalltablename WHEN \'test1\' THEN \'test\' ELSE \'test2\' END WHERE smalltableid = 1
SET @noTran = @noTran + DATEDIFF(MICROSECOND,@date,GETDATE())
SET @date = GETDATE()
BEGIN TRAN
UPDATE smalltable SET smalltablename = CASE smalltablename WHEN \'test1\' THEN \'test\' ELSE \'test2\' END WHERE smalltableid = 1
COMMIT TRAN
SET @withTran = @withTran + DATEDIFF(MICROSECOND,GETDATE())
SET @count = @count + 1
END
SELECT
@noTran / 1000000. AS Seconds_NoTransaction,@withTran / 1000000. AS Seconds_WithTransaction
Seconds_NoTransaction Seconds_WithTransaction
2.63200000 2.70400000
2.16700000 2.12300000
反转更新顺序可以保持相同的行为
, 在您发布的代码中,没有可测量的效果,但是事务确实对性能有影响,由于日志刷新提交分组,它们可以显着提高性能,或者由于管理不当的争用问题,它们可以显着降低性能。但最重要的是,当需要交易以确保正确性时,您不能跳过拥有它们。话虽这么说,相对于事务和try-catch块,您的模板实际上是非常糟糕的。 catch块中的事务必须具有三态逻辑检查XACT_STATE
返回值(-1、0、1),并正确处理注定的事务。有关示例,请参见异常处理和嵌套事务。
同样,永远不要将try-catch错误处理与返回代码错误处理混合使用。选择一个并坚持下去,最好是赶上。换句话说,您的存储过程应提高,而不返回-1。将异常与错误代码混合在一起会使代码成为维护和正确调用的噩梦。
, TL; DR-存储的Procdure包含两个处理3300万条记录的选择查询,我花了45秒钟执行,而没有事务处理,花了48秒钟。
免责声明:我编写了一个存储过程大约4个小时,并且遇到了一个对该问题的可衡量的答案(注意:这并不重要!)由于我正在处理的数据的敏感性,故意省略了查询逻辑中的空白用。
方法:此过程是使用两个查询开发的-一个执行大部分繁重的工作,另一个查询自行计算一个额外的字段,因此它不会尝试计算超出所需范围的更多字段。我将其分为两个步骤:
1)我用1个SQL SELECT编写了2个Common Table Expressions到一个临时表中,然后再次对其进行查询。我之所以必须这样做,是因为要求我实现的是几个标量值函数,否则它们将尝试在超过3,300万条记录(而不是355条)上运行该函数。
2)我在第一个查询之后附加了一个标量值函数,因此它不会尝试查找3000万条记录(如果您愿意的话,它会带来很大的不同)。
查询:出于读者的目的,我剪切了大部分查询(case语句)。
CREATE PROC GET_PAYMENT_SUMS_BY_CLIENT
AS
--Required for reporting in a specific Business Intelligence later; Optional
SET FMTONLY OFF;
BEGIN TRANSACTION
--Query 1
--This CTE checks over 30 million records
WITH CTE1 AS(
SELECT CASE VARIABLE
--170 case conditions go here
END AS TheType,Amount,PK1 FROM TABLE1),--THIS CTE Pivots the sums to get the data in the style I want it in
CTE2 AS(
SELECT PK1,[PIVOT1],[PIVOT2],[PIVOT3]
FROM
(SELECT * FROM CTE1) AS BaseTable --Alias was just to get it to execute
)
PIVOT(
SUM(Amount)
FOR TheType IN ([PIVOT1],[PIVOT3])
) AS PivotTable
)
)
SELECT TABLE2.NAME,CTE2.* INTO #TEMPORARY_TABLE
FROM CTE2
JOIN TABLE2 ON CTE2.PK1 = TABLE2.PK2
--Query 2
--Written to force the function to look at 355 records instead of 33 million
SELECT *,dbo.SCALAR_VALUED_FUNCTION(PK2) FROM #TEMPORARY_TABLE
COMMIT TRANSACTION
发现:
使用事务处理-如果使用事务处理逻辑,则从该集合产生的查询将花费48秒来处理包含170行的case语句中的超过3,300万条记录,按总和旋转数据,将数据放入临时表中并附加第一个查询运行后的标量值函数。
不使用事务-如果对代码中的注释行进行注释,则所有上述步骤将在45秒内完成。这比使用事务块快大约7%:3/45 = 0.0666 ....〜快7%。
结论:
尽管我的工作无法告诉您对10条记录进行相同的查询是否会产生相同比例的差异,但是它可以告诉您,当您开始使用更大的数据集和/或更复杂的查询时,它会变得越来越重要。
我知道这些信息对某个人有用!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。