从存储过程插入时避免锁定表

时间:2018-04-28 23:37:00

标签: sql sql-server tsql stored-procedures sql-server-2016

我想通过使用insert into从存储过程返回输出。出于性能原因,目标表是内存优化的表类型。 我现在发现,当存储过程正在运行时,受存储过程影响的行中的所有行都将保持锁定状态,直到存储过程完成。

示例:

insert into @ModifiedSecurities (SecurityID, AttributeTypeID)
    exec Securities.spSecuritiesImportBody
                @ProcessingID = @ProcessingID

在执行Securities.spSecuritiesImportBody期间(最多需要10分钟),所有受spSecuritiesImportBody个受影响的表行都会被锁定,直到存储过程完成为止(即使表格与输出无关)存储过程)。

虽然在单个insert语句中这种行为可能有意义,但我没有看到它的任何用途,因此想要摆脱这些锁。

有没有办法在不创建这些锁的情况下执行存储过程?

这是我制作的代码示例:

  1. 执行准备
  2. 运行代码
  3. 在代码运行时尝试从dbo.ProcessingsTesting中进行选择。由于表被锁定,因此无法实现。在dbo.UpdProcessing期间正在创建锁。但是,出于某种原因,锁定没有被释放。
  4. 选择* 来自dbo.ProcessingsTesting

    - 开始准备

    drop procedure dbo.UpdProcessing 
    drop table dbo.ProcessingsTesting
    drop procedure dbo.spSecuritiesImportBody  
    
    
    go
    
    
    create table dbo.ProcessingsTesting
    (
        ProcessingID int,
        EndDate datetime
    )
    
    insert into dbo.ProcessingsTesting
    (
        ProcessingID
    )
    select 1 union all
    select 2 union all
    select 3 union all
    select 4 union all
    select 5
    
    
    -- stored procedure
    go
    create procedure dbo.spSecuritiesImportBody  
    (
        @ProcessingID int
    )
    as
    begin
    
    
        exec dbo.UpdProcessing  
            @ProcessingID = @ProcessingID
    
    
        WAITFOR DELAY '00:03:00' 
    
    
        -- return data
    
        select 1, 2
    
    
    end
    
    
    -- stored procedure
    
    go
    create procedure dbo.UpdProcessing  
    (
        @ProcessingID int
    )
    as
    begin
    
    
        update dbo.ProcessingsTesting
        set EndDate = null
        where ProcessingID = @ProcessingID
    
    
    end
    

    - 准备结束

    -- run the code 
    
    declare @ModifiedSecurities table
    (
        [SecurityID] [int] NOT NULL,
        [AttributeTypeID] [smallint] NOT NULL
    )
    
    
    insert into @ModifiedSecurities (SecurityID, AttributeTypeID)
        exec  dbo.spSecuritiesImportBody 
            @ProcessingID = 1
    

2 个答案:

答案 0 :(得分:1)

除非您开始并提交显式事务,否则锁定将保留在已修改的行上,直到最外面的class MyComponent extends React.Component { toggle = () => document.body.classList.toggle('mobileNavActive'); render() { return <button onClick={this.toggle}>toggle</button>; } } 语句完成。您可以向INSERT...EXEC proc添加显式事务(或使用dbo.UpdProcessingEXEC dbo.UpdProcessing围绕BEGIN TRAN)以在COMMIT之前释放已更新行的锁定完成:

INSERT...EXEC

虽然这会提供所需的结果,但对我来说,在同一存储过程中更新与ALTER PROCEDURE dbo.UpdProcessing ( @ProcessingID int ) AS BEGIN TRAN; UPDATE dbo.ProcessingsTesting SET EndDate = null WHERE ProcessingID = @ProcessingID COMMIT; GO 结果无关的数据对我来说没有多大意义。似乎应该独立调用procs,因为它们执行不同的功能。

答案 1 :(得分:0)

在程序spSecuritiesImportBody上你应该更改执行更新exec dbo.UpdProcessing
        @ProcessingID = @ProcessingID to 执行dbo.UpdProcessing @ProcessingID因为没有意义这样使用。

您无法避免锁定,因为MSSQL服务器对行,表,页面使用锁定,以确保在服务器执行有关数据库上该记录的语句时不更改数据。