2

Я знаю, что эта изоляция снимка исправит эту проблему, но мне интересно, безопасен ли 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, это может пойти не так в этом случае? Может ли он вернуться:

  1. Более одного ряда, хотя я просил TOP 1?
  2. Нет строк, даже если они существуют и были совершены?
  3. Хуже всего, строка, которая не удовлетворяет предложению WHERE?

Я сделал много читал об этом в Интернете, но только репродукции избыточного или недостаточного подсчета аномалий я видел (one, two) включают сканирование. Это касается только запросов. Jeff Atwood has a post об использовании NOLOCK, который дал хорошее обсуждение. Я был особенно заинтересован в комментарии Рик Townsend:

Во-вторых, если вы читали грязные данные, то риск запуска является чтения совершенно неправильно строку. Например, если вашего выбор читает индекс для поиска своей строки, то обновление изменяет расположения строк (например, из-за страницу раскол или обновление для кластерного индекса ), когда ваш выбор идет чтобы прочитать фактическую строку данных, это либо уже не существует, либо другая строка в целом!

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


Update:

Я пытаюсь выяснить how snapshot isolation works. Кажется, что он основан на строке, где транзакции читают таблицу (без общей блокировки!), Найдите интересующую их строку, а затем посмотрите, нужно ли им получить старую версию строки из хранилища версий в tempdb.

Но в моем случае ни одна строка не будет иметь более одной версии, поэтому хранилище версий кажется довольно бессмысленным. И если строка была найдена без общей блокировки, как она отличается от использования NOLOCK?

ответ

7

Использование NOLOCK или READ UNCOMMITTED означает, что вы отказываетесь от какой-либо гарантии согласованности. Период.

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

Не уверен, что это применимо, неясно, чего вы пытаетесь достичь с помощью своего запроса/таблицы, но, возможно, эта статья может помочь: Using tables as Queues.

Обновлено
Если NOLOCK чтение будет читать несогласованное состояние (например, читать несвежий некластеризованный ключ индекса и преследовать его за отсутствующую строку в кластерном индексе) снимок чтение найдет «недостающее» строка в хранилище версий. Для стабильных данных считывание моментального снимка идентично чтению nolock. Магия хранилища версий вступает в игру всякий раз, когда данные изменяются (незафиксированные обновления), поскольку считывание моментального снимка переходит в хранилище версий и находит «старые» значения (стабильные и последовательные), где чтение nolock будет идти с haywire и chase pointer лала.

+0

Ах, предложение OUTPUT очень круто, спасибо. Мне это не нужно в этом конкретном столе, но я могу вспомнить какой-то будущий код, в котором я мог бы его использовать. И я принимаю ваше решение. Я уже испытал влияние различных планов запросов - тупик не возникает, пока не будет достаточно строк, чтобы сделать два файла лучше, чем полное сканирование. Честно говоря, я уже склонялся к изоляции снимков. Но документировать недокументированное поведение мне интересно, даже если я не использую его в производстве. :) –

+0

Обновленный оригинальный пост с другим вопросом, спасибо. –

+0

Итак, я согласен с тем, что мы не хотим «читать устаревший некластеризованный индексный ключ и преследовать его до недостающей строки в кластерном индексе». Вопрос в том, действительно ли это произойдет без UPDATE в любых строках? Все, что я делаю, это вставка, поэтому будут обновляться только метаданные, а не данные в любых строках. Я бы подумал, что SQL Server будет иметь некоторый механизм согласованности на низком уровне, чтобы предотвратить повреждение метаданных, даже при использовании NOLOCK (что довольно концепция высокого уровня) ..? –

1

В этом случае вы должны быть в безопасности с NOLOCK. Еще одна мысль: добавление значения в качестве включенного столбца индекса Ix должно исключать поиск на Cx.

create nonclustered index Ix on Data (Id, Date) include (Value) 
+0

Не могли бы вы рассказать о том, почему вы считаете, что это безопасно, в свете изложенных выше проблем? Кроме того, я рассмотрел включение неинтерактивных столбцов в индекс, но на самом деле они довольно широкие (их больше, чем один), и он использовал бы значительное пространство. И дублирование может вывести из кэша больше полезных вещей. –