Я работаю над несколькими службами в. 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();
}
}
}
Я вижу, что здесь есть выбор *, я понимаю, что это не очень хорошая практика.