Избегайте блокировки таблиц при вставке из хранимой процедуры - PullRequest
0 голосов
/ 29 апреля 2018

Я хочу вернуть вывод из хранимой процедуры с помощью вставки в. Из соображений производительности таблица назначения является типом таблицы, оптимизированной для памяти. Теперь я выяснил, что во время работы хранимой процедуры все строки, затронутые хранимой процедурой, остаются заблокированными до завершения хранимой процедуры.

Пример:

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

Во время выполнения Securities.spSecuritiesImportBody (что занимает до 10 минут) все строки таблицы, на которые влияют spSecuritiesImportBody, блокируются до завершения хранимой процедуры (даже таблицы не имеют никакого отношения к выводу хранимой процедуры).

Хотя в одном операторе вставки это поведение может иметь смысл, я не вижу его смысла и поэтому хочу избавиться от этих блокировок.

Есть ли способ выполнить хранимую процедуру, не создавая эти блокировки?

Вот пример кода, который я сделал:

  1. Выполнить подготовку
  2. Запустите код
  3. Попробуйте выбрать из dbo.ProcessingsTesting во время выполнения кода. Это будет невозможно, так как стол заблокирован. Блокировка создается во время dbo.UpdProcessing. Однако по какой-то причине блокировка не снимается.

выберите * от 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 голосов
/ 29 апреля 2018

Если вы не начнете и не совершите явную транзакцию, блокировки будут изменяться в измененных строках до тех пор, пока не завершится самый дальний оператор INSERT...EXEC. Вы можете добавить явную транзакцию в процесс dbo.UpdProcessing (или окружить EXEC 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

Хотя это даст желаемые результаты, для меня не имеет большого смысла обновлять данные, не связанные с результатами SELECT, в той же хранимой процедуре. Похоже, что процессы должны вызываться независимо, поскольку они выполняют разные функции.

0 голосов
/ 29 апреля 2018

В процедуре spSecuritiesImportBody вы должны изменить исполняемое обновление exec dbo.UpdProcessing
@ProcessingID = @ProcessingID для Exec dbo.UpdProcessing @ProcessingID, потому что нет смысла использовать подобное.

Вы не можете избежать блокировки, потому что сервер MSSQL использует блокировку строки, таблицы, страниц, чтобы гарантировать, что вы не меняете данные, когда сервер выполняет операторы, относящиеся к этой записи в базе данных.

...