Я знаю, что эта изоляция снимка исправит эту проблему, но мне интересно, безопасен ли NOLOCK в этом конкретном случае, чтобы я мог избежать накладных расходов.ЯВЛЯЕТСЯ ЧИТАЕМОЙ НЕОБХОДИМЫЙ/NOLOCK в этой ситуации?
У меня есть таблица, которая выглядит примерно так:
drop table Data
create table Data
(
Id BIGINT NOT NULL,
Date BIGINT NOT NULL,
Value BIGINT,
constraint Cx primary key (Date, Id)
)
create nonclustered index Ix on Data (Id, Date)
Там не было изменений в таблице, когда-либо. Удаления могут возникать, но они не должны бороться с SELECT, потому что они влияют на другой, более старый конец таблицы. Вставки являются регулярными, а разбиение страниц на индекс (Id, Date) чрезвычайно распространено.
У меня есть тупиковой ситуации между стандартным INSERT и SELECT, который выглядит следующим образом:
select top 1 Date, Value from Data where Id = @p0 order by Date desc
, поскольку ВСТАВИТЬ получает блокировку на Cx (Дата, Id, Value), а затем Ix (Id, дата), но SELECT получает блокировку на Ix (Id, Date), а затем Cx (Date, Id, Value). Это связано с тем, что SELECT сначала ищет Ix, а затем присоединяется к поиску на Cx.
Обмен кластеризованным и некластеризованным индексом приведет к поломке этого цикла, но это не приемлемое решение, поскольку оно будет вводить циклы с другими (более сложными) SELECT.
Если я добавлю NOLOCK в SELECT, это может пойти не так в этом случае? Может ли он вернуться:
- Более одного ряда, хотя я просил TOP 1?
- Нет строк, даже если они существуют и были совершены?
- Хуже всего, строка, которая не удовлетворяет предложению WHERE?
Я сделал много читал об этом в Интернете, но только репродукции избыточного или недостаточного подсчета аномалий я видел (one, two) включают сканирование. Это касается только запросов. Jeff Atwood has a post об использовании NOLOCK, который дал хорошее обсуждение. Я был особенно заинтересован в комментарии Рик Townsend:
Во-вторых, если вы читали грязные данные, то риск запуска является чтения совершенно неправильно строку. Например, если вашего выбор читает индекс для поиска своей строки, то обновление изменяет расположения строк (например, из-за страницу раскол или обновление для кластерного индекса ), когда ваш выбор идет чтобы прочитать фактическую строку данных, это либо уже не существует, либо другая строка в целом!
Возможно ли это с помощью вставок и обновлений? Если это так, то я думаю, что даже мои поиски в таблице только для вставки могут быть опасными.
Update:
Я пытаюсь выяснить how snapshot isolation works. Кажется, что он основан на строке, где транзакции читают таблицу (без общей блокировки!), Найдите интересующую их строку, а затем посмотрите, нужно ли им получить старую версию строки из хранилища версий в tempdb.
Но в моем случае ни одна строка не будет иметь более одной версии, поэтому хранилище версий кажется довольно бессмысленным. И если строка была найдена без общей блокировки, как она отличается от использования NOLOCK?
Ах, предложение OUTPUT очень круто, спасибо. Мне это не нужно в этом конкретном столе, но я могу вспомнить какой-то будущий код, в котором я мог бы его использовать. И я принимаю ваше решение. Я уже испытал влияние различных планов запросов - тупик не возникает, пока не будет достаточно строк, чтобы сделать два файла лучше, чем полное сканирование. Честно говоря, я уже склонялся к изоляции снимков. Но документировать недокументированное поведение мне интересно, даже если я не использую его в производстве. :) –
Обновленный оригинальный пост с другим вопросом, спасибо. –
Итак, я согласен с тем, что мы не хотим «читать устаревший некластеризованный индексный ключ и преследовать его до недостающей строки в кластерном индексе». Вопрос в том, действительно ли это произойдет без UPDATE в любых строках? Все, что я делаю, это вставка, поэтому будут обновляться только метаданные, а не данные в любых строках. Я бы подумал, что SQL Server будет иметь некоторый механизм согласованности на низком уровне, чтобы предотвратить повреждение метаданных, даже при использовании NOLOCK (что довольно концепция высокого уровня) ..? –