首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >SQL Server如何处理事务性插入中的SELECT语句?

SQL Server如何处理事务性插入中的SELECT语句?
EN

Stack Overflow用户
提问于 2011-06-28 00:10:53
回答 3查看 1.1K关注 0票数 2

作为零售结账流程的一部分,有一个事务性存储过程,它从18个表中选择每个表,并将它们插入到单独的数据库中,以供以后的大型机处理。此过程显示了一些奇怪的计时行为,我认为这是因为对SQL Server中事务工作方式的根本误解。

我认识到这不是解决这个问题的最佳架构,新的解决方案正在开发中,但同时,我需要改进这个过程。

存储过程根据用户请求运行,如下所示:

代码语言:javascript
复制
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

日志记录如下所示:

代码语言:javascript
复制
Table1      0.2 seconds 354 rows
Table2      7.4 seconds 35 rows
Table3      3.9 seconds 99 rows

在行的数量或连接的复杂度与时间之间没有明确的相关性。

我的问题是-在这样一个漫长的过程中,交易的影响是什么?子选择中的所有表在开始时都被锁定了吗?一次一个?它是否在等待源表可用于锁,这是导致等待的原因?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-06-28 01:01:32

在什么隔离级别下?

对于写部分(插入部分),无论隔离级别如何,一切都是一样的:所有插入的行都以X模式锁定,直到事务结束。行锁可以escalate到表锁。

如果隔离级别保留为默认的读取提交快照,并且数据库上的read-committed-snapshot-isolation选项处于OFF状态,则会发生如下情况:每次选择都会以S模式锁定一行,然后立即释放它。

在repeatable read隔离下,由SELECT获取的S锁将一直保留到事务结束,并且它们可能升级为表S锁。

在serializable read隔离下,SELECT将获取范围锁而不是行锁,并将它们保留到事务结束。同样,可能会发生锁升级。

在snapshot isolation下,SELECTs根本不获取任何锁(忽略模式稳定性锁的一些技术细节),它们将从版本tore中读取任何锁定的行。读取的版本对应于事务开始时的值的快照。

在read committed isolation下,如果在数据库上启用了read-committed-snapshot-isolation,那么SELECTs将不会获得任何锁,如果行被锁定,它们将从版本存储中读取。读取的版本对应于语句开头的值的快照。

现在回到您的问题,为什么您会看到性能上的差异?与任何性能问题一样,最好应用调查方法,而Waits and Queues是一个很好的方法。一旦您调查了根本原因,就可以提出适当的解决方案。

票数 2
EN

Stack Overflow用户

发布于 2011-06-28 00:27:26

使用默认的READ COMMITTED隔离级别,读(共享)锁将仅在每个SELECT期间存在。不是为了交易。

要改变这一点,您需要更高级别的REPEATABLE_READ来保持共享(读)锁,直到事务结束。

备注:

  • 锁定粒度(行、页等)与此持续时间是分开的,其他进程将能够读取SELECTed tables

您的插入持续时间将受到一大堆条件的影响。其中一些:

对于要作为目标表上的INSERT

  • triggers的一部分进行维护的SELECT processes

  • transaction

  • 索引,请按照我在此处提到的所有内容写入和读取

日志文件:

编辑:

经过深思熟虑后,您是否会更好地使用sp_getapplock等来维护应用程序级别的并发。

票数 4
EN

Stack Overflow用户

发布于 2011-06-28 00:39:43

在我看来,在这种情况下,使用或不使用事务并不会对性能产生太大影响。我建议您需要分别调优每个insert (考虑到insert的性能不仅取决于子选择,还取决于insert-目标表中的索引越多,insert性能就越差;您还可能为某些表选择了错误的聚集索引)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6495736

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档