Является ли READ UNCOMMITTED / 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
потому что INSERT получает блокировку для Cx (Date, Id; Value) и затем Ix (Id, Date), но SELECT получает блокировку для Ix (Id, Date) и затем Cx (Date, Id; Value). Это потому, что SELECT сначала ищет на Ix, а затем присоединяется к поиску на Cx.
Замена кластеризованного и некластеризованного индекса нарушит этот цикл, но это неприемлемое решение, поскольку оно будет вводить циклы с другими (более сложными) SELECT.
Если я добавлю NOLOCK в SELECT, может ли он пойти не так в этом случае? Может ли это вернуться:
- Более одного ряда, хотя я просил ТОП 1?
- Нет строк, хотя один существует и был зафиксирован?
- Хуже всего то, что строка не удовлетворяет предложению WHERE?
Я много читал об этом в Интернете, но единственные репродукции аномалий избыточного или недостаточного количества, которые я видел ( один, два), включают сканирование. Это включает только поиск. Джефф Этвуд написал статью об использовании NOLOCK, которая вызвала хорошую дискуссию. Меня особенно заинтересовал комментарий Рика Таунсенда:
Во-вторых, если вы читаете грязные данные, вы рискуете прочитать совершенно неверную строку. Например, если ваш выбор считывает индекс, чтобы найти вашу строку, то обновление изменяет расположение строк (например, из-за разбиения страницы или обновления кластеризованного индекса), когда ваш выбор идет, чтобы прочитать фактическую строку данных или его там больше нет, или совсем другой ряд!
Это возможно только со вставками и без обновлений? Если так, то я думаю, что даже мои поиски в таблице только для вставки могут быть опасными.
Обновить:
Я пытаюсь выяснить, как работает изоляция снимка. Похоже, что он основан на строках, где транзакции читают таблицу (без общей блокировки!), Находят интересующую их строку, а затем проверяют, нужно ли им получить старую версию строки из хранилища версий в базе данных tempdb.
Но в моем случае ни в одной строке не будет более одной версии, поэтому хранилище версий кажется довольно бессмысленным. И если строка была найдена без общей блокировки, чем она отличается от использования NOLOCK?
2 ответа
Использование NOLOCK или READ UNCOMMITTED означает, что вы отказываетесь от какой-либо гарантии согласованности. Период.
Если вам нужна последовательность, не делайте грязного чтения. Все ваше объяснение основано на недокументированном поведении, которое может измениться в будущих выпусках, и, что еще хуже, на конкретных планах доступа, которые вы ожидаете для своего запроса. Оптимизатор запросов может свободно выбирать любой план, который сочтет нужным, и любые предположения, которые вы делаете, могут быть сорваны при производстве. Итак, вернемся к исходной точке: не делайте грязных чтений, если вы не готовы столкнуться с последствиями.
Не уверен, что это применимо, не ясно, чего вы пытаетесь достичь с помощью вашего запроса / таблицы, но, возможно, эта статья может помочь: Использование таблиц в качестве очередей.
обновленный
Там, где чтение NOLOCK считывает несогласованное состояние (например, читает устаревший некластеризованный индексный ключ и преследует его до отсутствующей строки в кластеризованном индексе), при считывании моментального снимка будет найдена "пропущенная" строка в хранилище версий. Для стабильных данных чтение снимка идентично чтению nolock. Волшебство хранилища версий вступает в игру всякий раз, когда данные изменяются (незафиксированные обновления), потому что считанные снимки попадают в хранилище версий и находят "старые" значения (стабильные и согласованные), при которых чтение nolock могло бы привести к сбою и указателям погони в Лала Лэнд.
В этом случае вы должны быть в безопасности с NOLOCK. Еще одна мысль: добавление значения в качестве включенного столбца в индексе Ix должно исключить поиск по Cx.
create nonclustered index Ix on Data (Id, Date) include (Value)