Как я могу избавиться от этого тупика? - PullRequest
3 голосов
/ 26 октября 2011

У меня есть 2 запроса, которые участвуют в ситуации взаимоблокировки, показанной на графике взаимоблокировок ниже.(Seitensperre означает блокировку страницы)

Запрос в процессе 55 является жертвой тупика.Это выбор, который включает в себя порядок и оплату таблиц.

В запросе процесса 95 содержится несколько запросов. В начале ist делает пару выборок для сохранения некоторых значений в переменных (доступ к порядку таблиц) Затем он обновляет порядок столов и после этой оплаты за стол.

Я не понимаю, как может возникнуть тупик в этой ситуации.Можете ли вы объяснить, что вызвало тупик и что я могу с этим сделать?Я думаю, мне просто трудно читать тупиковую диаграмму.

Вот ресурсы, вовлеченные в процесс.Вот запрос на обновление (процесс 95)

ALTER   PROCEDURE [dbo].[updateOrderDetails]
(
    @id_order               int,
    @customerComment        NText,
    @salutationBilling      nvarchar(50) = '00',
    @companyNameBilling     nvarchar(100)= ''

        ...some more Parameters
)
AS
DECLARE @user_change int, @id_orderAddress int,
        @id_voucherType int, @id_orderPayment int, @id_paymentMode int


SET NOCOUNT ON;
SET ANSI_NULLS ON

SELECT @user_change = 0
SELECT @id_orderAddress = 0
SELECT @id_voucherType = 0
SELECT @id_orderPayment = 0
SELECT @id_paymentMode = 0


SELECT @user_change = id FROM user
 WHERE logonName = @user_str

SELECT @id_orderAddress = id_orderAddress FROM order
 WHERE [id] = @id_order

SELECT @id_voucherType = [id] FROM voucherType
 WHERE [name] = @voucherTypeName


SELECT @id_orderPayment = [id_orderPayment] FROM order 
 WHERE [id] = @id_order 

SELECT @id_paymentMode = [id] FROM paymentMode
 WHERE [name] = @paymentModeName


IF @user_change = 0 GOTO ERR
IF @id_voucherType = 0 GOTO ERR

UPDATE order
SET
[id_voucherType]        =       @id_voucherType,
[customerComment]       =       @customerComment,
[causeOfCancellation]   =       @causeOfCancellation
...some more fields to update

WHERE
[id] = @id_order

IF @id_orderAddress = 0 GOTO ERR

UPDATE Address
SET
[salutationBilling]     =    @salutationBilling,
[companyNameBilling]    =    @companyNameBilling,
[firstNameBilling]      =    @firstNameBilling
...some more fields to update
WHERE
[id] = @id_orderAddress

IF @id_orderPayment = 0 OR @id_paymentMode = 0 GOTO ERR
UPDATE Payment
SET
[id_paymentMode]        =   @id_paymentMode,
[customerBankDepositor] =   @customerBankDepositor,
[customerBank]          =   @customerBank,
[customerBankCode]      =   @customerBankCode,
...some more fields to update
WHERE
[id] = @id_orderPayment

IF @@Error > 0 Goto ERR


RETURN 0

ERR:

return  -1;
SET QUOTED_IDENTIFIER ON

Вот запрос на выбор (процесс 55)

ALTER  PROCEDURE [dbo].[searchOrders]
(
  @SelectType           INT
 ,@searchB2B            INT
 ,@VoucherNumber        NVARCHAR(50)  = null
 ,@FirstNameBilling     NVARCHAR(100) = null
    ... some more parameters
)

AS

SET NOCOUNT ON;

IF  @SelectType = 0 and LEN(@VoucherNumber) > 0
 BEGIN
    SELECT DISTINCT  (o.id)
                    ,o.voucherNumber
                    ...some more columns

    FROM             order AS o
    LEFT JOIN        orderAssignment AS oa  ON o.id = oa.id_order
    LEFT JOIN        voucherType AS vt      ON o.id_voucherType = vt.id
    LEFT JOIN        Payment AS op      ON o.id_orderPayment = op.id
    LEFT JOIN        paymentMode AS pm      ON op.id_paymentMode = pm.id
    LEFT JOIN        orderAddress AS addr   ON o.id_orderAddress = addr.id
    LEFT JOIN        user AS u1             ON o.user_change = u1.id
    LEFT JOIN        user as u2             ON oa.id_user = u2.id   
    LEFT JOIN        b2bAccount as b2b      ON o.id_b2bAccount = b2b.id


    WHERE            o.voucherNumber like @VoucherNumber
    AND              o.isB2B = @searchB2B
 END
...some more cases depending on @SelectType but the actual query is with @SelectType = 0

RETURN

SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON

Ответы [ 3 ]

3 голосов
/ 26 октября 2011

Было бы полезно, если бы вы могли опубликовать операторы, участвующие в каждом процессе, но здесь идет речь ...

Если операторы SELECT выполняют агрегирование, они могут получить блокировки таблиц.Вы можете попробовать использовать подсказку WITH(NOLOCK), если это позволяет ваш вариант использования.

Операторы UPDATE действительно зависят от объема изменяемых записей - избирательности условия WHERE и от того,эффективно использовать индексы или нет.

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

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

1 голос
/ 31 октября 2011

В конце оказалось, что это проблема с кодом вызова. Это сложно объяснить, но в основном транзакция была открыта и передана нескольким методам.

Я удалил транзакцию, и тупики исчезли.

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

0 голосов
/ 31 октября 2011

Внутри транзакции, меняйте запросы как

SELECT @id_orderAddress = id_orderAddress FROM order
 WHERE [id] = @id_order

к следующему:

SELECT @id_orderAddress = id_orderAddress FROM order WITH(UPDLOCK)
 WHERE [id] = @id_order

Это гарантирует, что последующие обновления той же строки 'order' не вызовут взаимоблокировок - строки 'order' заблокированы уже в начале транзакции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...