作为零售结算流程的一部分,有一个事务存储过程,它从18个表中的每个表中进行选择,并将它们插入到单独的数据库中,以便以后进行大型机处理。这个过程显示了一些奇怪的计时行为,我认为这是因为对SQL Server中事务的工作方式存在根本性的误解。
我认识到这不是这个问题的最佳架构,而且正在开发新的解决方案,但与此同时,我需要改进这个过程。
存储过程基于用户请求运行,如下所示:
BEGIN TRANSACTION
INSERT INTO Table1
(Column1,
Column2,
Column3,
Column4,
Column5,
Column6,
Column7,
Column8)
SELECT
Column1,
Column2,
Column3,
Column4,
Column5,
Column6,
Column7,
Column8
FROM
OLTPTable T
INNER JOIN
LookupTable1 L
ON
T.Foreign = L.Key
INSERT INTO Table2
(Column1,
Column2,
Column3)
SELECT
Column1,
Column2,
Column3
FROM
OLTPTable2 T
INNER JOIN
LookupTable2 L
ON
T.Foreign = L.Key
INSERT INTO Table3
(Column1,
Column2,
Column3,
Column4,
Column5,
Column6)
SELECT
Column1,
Column2,
Column3,
Column4,
Column5,
Column6
FROM
OLTPTable3 T
INNER JOIN
LookupTable3 L
ON
T.Foreign = L.Key
-- Through Table 18 and OLTP Table 18
COMMIT TRANSACTION
日志记录看起来像这样:
Table1 0.2 seconds 354 rows
Table2 7.4 seconds 35 rows
Table3 3.9 seconds 99 rows
行数或连接的复杂性与时间之间没有明确的相关性。
我的问题是 - 在这样一个漫长的程序中,交易的影响是什么?是否在开始时锁定子选择中的所有表?一次一个?它是否在等待源表可用于锁定,这导致等待?
答案 0 :(得分:4)
使用默认的READ COMMITTED隔离级别,Read(共享)锁定将在每个SELECT的持续时间内存在。不适用于交易。
要更改此设置,您需要更高的REPEATABLE_READ才能保持共享(读取)锁定,直到事务结束。
注意:
您的INSERT持续时间将受到大量条件的影响。一些,:
编辑:
经过深思熟虑后,使用sp_getapplock等可以更好地维护应用级并发性。
答案 1 :(得分:2)
在我看来,在这种情况下,使用或不使用交易不会对性能造成太大影响。我建议您需要单独调整每个插入(考虑到插入的性能不仅取决于子选择,还取决于插入 - 目标表中的索引越多,插入性能越差;您可能也选择了错误某些表的聚簇索引)。
答案 2 :(得分:2)
在什么样的隔离级别?
对于写入部分(插入),无论隔离级别如何,一切都是相同的:所有插入的行都以X模式锁定,直到事务结束。行锁可以escalate到表锁。
如果隔离级别保留在默认的 read committed 并且数据库上的read-committed-snapshot-isolation选项为OFF,则会发生如下情况:每个select将锁定一行在S模式下的时间并将立即释放。
在可重复读取隔离下,SELECTs获取的S锁将保留到事务结束,并且它们可能会升级到表S锁。
在可序列化读取隔离下,SELECT将获取范围锁而不是行锁,并将保留它们直到事务结束。同样,可能会发生锁定升级。
在快照隔离下,SELECTs根本没有获取任何锁(忽略了一些关于模式稳定性锁的技术细节),它们将从版本tore中读取任何锁定的行。读取的版本对应于事务开始时的值的快照。
在数据库上启用读取 - 提交 - 快照 - 隔离时,读取已提交隔离,SELECT将不会获取任何锁定,如果行被锁定,它们将从版本存储读取。读取的版本对应于语句开头的值的快照。
现在回到你的问题,为什么你会看到性能上的差异?与任何性能问题一样,最好采用调查方法,Waits and Queues是一个很好的方法。一旦你研究了根本原因,就可以提出一个合适的解决方案。