繁体   English   中英

防止在事务中锁定数据库

[英]Preventing from locking database in transaction

我有用于更新和插入大量数据的查询

update [TableA]
set ColumnA1 = 'ValueA1'

DECLARE @MyCursor CURSOR;
DECLARE @MyField char(16);
BEGIN
    SET @MyCursor = CURSOR FOR
    select  ColumnA1 from [TableA]
        Where ColumnA2 = ValueA2  

    OPEN @MyCursor 
    FETCH NEXT FROM @MyCursor 
    INTO @MyField

    WHILE @@FETCH_STATUS = 0
    BEGIN

      FETCH NEXT FROM @MyCursor 
      INTO @MyField 

      Insert Into TableB(ColumnB1, ColumnB2, ColumnB3, ColumnB4, ColumnB5, ColumnB6)
      Values(@MyField, ValueB1, ValueB2, ValueB3, ValueB4, ValueB5)
    END; 

    CLOSE @MyCursor ;
    DEALLOCATE @MyCursor;
END;

如您所见,我首先更新TableA,然后使用更新的TableA记录将一些日志信息插入TableB。 我想以事务方式执行整个sql命令。 我担心使用begin transaction锁定整个sql server数据库。 我已经使用了Entity Framework,但不知道如何在不锁定sql server的情况下处理这种命令。

根据Hamlets的评论,没有“整个数据库” 锁定 最接近的可能是将数据库置于单用户模式

但是,对高​​度竞争的数据的行或表持有广泛的(排他性)锁将损害同时尝试读取已提交的数据的其他查询或其他编写器的性能。

例如,由于下面的更新可能会更改所有行,因此几乎可以肯定的是,TableA上会出现TABLOCK ,因此,如果将整个已发布的SQL包装在事务中,则TableA在游标期间也将被锁定。

UPDATE [TableA]
SET ColumnA1 = 'ValueA1';

游标本身似乎是不必要和不想要的-尽可能将RBAR方法替换为基于集合的方法。 以下插入内容应等效:

INSERT Into TableB(ColumnB1, ColumnB2, ColumnB3, ColumnB4, ColumnB5, ColumnB6)
SELECT ColumnA1, ValueB1, ValueB2, ValueB3, ValueB4, ValueB5
FROM [TableA]
WHERE ColumnA2 = ValueA2;

为了回答您的最后一个问题,默认情况下,Entity Framework将.SaveChanges()调用包装到事务中 -直到这一点为止,仅在内存中跟踪对DbContext所做的所有更改。

IMO,ORMS之类的EntityFramework对于大批量/批处理操作(例如您在此处介绍的sql)而言并不理想,因为您对结果Sql的控制很少。

如果您打算将此批量工作移至.Net,我可以建议

您将可以使用共享的SqlConnection来控制上述事务(SqlBulkCopy具有使用SqlConnection的构造函数)。

顺便说一句,如果您的要求不要求您在事务下执行整个操作序列,则可以考虑将更新+插入批量处理为每次提交<5000个,以避免发生锁升级问题

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM