Почему запрос на выборку попадет в тупик? - PullRequest
0 голосов
/ 09 июля 2020

Я работаю над несколькими службами в. net, которые используют SQL Server 2016. Сегодня у меня несколько раз возникала тупиковая ошибка, которую я пытаюсь выяснить. Жертва взаимоблокировки была хранимой процедурой, которая выполняет следующий запрос. Я думал, что использование updlock и сериализации внутри транзакции заблокирует строки для обновлений до тех пор, пока транзакция не будет завершена, и если во время блокировки будет выполняться запрос выбора, он все равно сможет получить зафиксированные данные. Я не думал, что с этим запросом выбора вообще возможна тупиковая ситуация ни при каких обстоятельствах, я имею в виду, что он не пытается изменить данные. Кто-нибудь видит, что я здесь сделал не так? Ошибка: транзакция (идентификатор процесса 337) зашла в тупик на ресурсах с другим процессом и была выбрана жертвой взаимоблокировки. Повторите транзакцию.

select  
    pm.DateKey, 
    sum(mm.Numerator) as Numerator,
    sum(mm.Denominator) as Denominator
from fact.MonthlyMeasures mm
join dim.PatientMonth pm on pm.PatientMonthKey = mm.PatientMonthKey   
where 
    mm.MeasureID = @MeasureID and 
    mm.CenterKey = @CenterKey
group by
    pm.DateKey    
order by
    pm.DateKey

В коде. net есть по одной ячейке, где обновляются таблицы fact.MonthlyMeasures и dim.PatientMonth и выполняется блокировка. Они оба следуют одному и тому же формату, поэтому вот код для одной таблицы:

public void UpsertPatientMonth(DBPatientMonth patientmonth)
{
    using (var dbConn = _connection.CreateConnection())
    {
        try
        {
            dbConn.BeginTransaction();

            string selectLock = $"select * from dim.PatientMonth with (updlock, serializable) where PatientKey = {patientmonth.PatientKey} and DateKey = {patientmonth.DateKey}";

            var existingPM = dbConn.Query<DBPatientMonth>(selectLock).FirstOrDefault();

            if (existingPM == null)
            {
                patientmonth.insert_date = DateTime.Now;
                dbConn.Insert(patientmonth);
            }
            else
            {
                //removed for brevity
                dbConn.Save(patientmonth);
            }
        }
        catch(Exception ex)
        {
            throw new CustomException("Error updating PatientMonth. Message: " + ex.Message, "upsertPatientMonth");
        }
        finally
        {
            dbConn.CompleteTransaction();
        }        
    }
}

Я вижу, что здесь есть выбор *, я понимаю, что это не очень хорошая практика.

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