Конечно, вы можете прочитать подмножество или все неподтвержденные данных, пораженных между началом операции и фиксацией или откатом. Это своего рода точка NOLOCK
- чтобы вы могли читать данные, которые не были выполнены, так что вам не нужно ждать авторов и избегать размещения большинства блокировок, чтобы писателям не приходилось ждать вас.
Доказательство # 1
Это очень легко доказать. В одном окне, создать эту таблицу:
CREATE TABLE dbo.what(id INT);
Во втором окне, выполните этот запрос:
DECLARE @id INT;
WHILE 1 = 1
BEGIN
SELECT @id = id FROM dbo.what WITH (NOLOCK) WHERE id = 2;
IF @id = 2
BEGIN
PRINT @id;
BREAK;
END
END
Теперь вернитесь к первому окну, и начать намеренно длительную транзакцию, но рулет его обратно:
BEGIN TRANSACTION;
GO
INSERT dbo.what SELECT 2;
GO 10000
ROLLBACK TRANSACTION;
Как только вы начинаете это в первом окне запроса во втором окне остановится и будет выплюнуть неизрасходованного значение, которое было зачитано.
Доказательство # 2
Это в первую очередь оспорить @ комментарий Бламу в выше, что я не согласен с:
На самом деле я думаю, что вы могли прочитать все 100 не только подмножество до к фиксации или откату.
Вы, безусловно, можете читать подмножества строк, затронутых транзакцией. Попробуйте следующий, похожий пример, на этот раз вставляя наборы 100 в таблицу 1000 раз и получая счет в запросе с помощью (NOLOCK)
. Окно # 1 (если вы еще не испытаны доказательство # 1 выше):
CREATE TABLE dbo.what(id INT);
Window # 2:
DECLARE @c INT;
WHILE 1 = 1
BEGIN
SELECT @c = COUNT(*) FROM dbo.what WITH (NOLOCK) WHERE id = 2;
IF @c > 0
PRINT @c;
IF @c > 10000
BREAK;
END
Назад в Window # 1:
BEGIN TRANSACTION;
GO
INSERT dbo.what SELECT TOP (100) 2 FROM sys.all_objects;
GO 1000
ROLLBACK TRANSACTION;
Window # 2 будет вращаться, пока вы не начнете транзакцию. Как только вы это сделаете, вы начнете видеть подсчеты. Но они не будут насчитывать 100 (не считая 100 000, все или ничего не требуют @Blam, похоже, делают).Вот мои сокращенные результаты:
1
10
12
14
17
19
23
25
29
...
85
87
91
95
98
100
100
...
9700
9700
9763
9800
9838
9900
9936
10000
10000
10000
10080
NOLOCK
запрос явно не ждать, пока какой-либо один оператор, чтобы закончить перед чтением данных, не говоря уже о всей транзакции. Таким образом, вы можете получить данные в любом состоянии потока, независимо от того, сколько строк влияет на каждый оператор, и независимо от того, сколько операторов находится во всей транзакции.
Другие побочные эффекты
Есть также случаи, когда NOLOCK
может skip rows, or read the same row twice, в зависимости от типа сканирования, а когда другая транзакция генерации расщепляется страниц. По существу, происходит то, что запрос (NOLOCK)
считывает данные, другие записи могут фактически перемещать данные в другое место - поскольку они могут - либо перемещать строку, которую вы уже прочитали, до точки вперёд в вашем сканировании, либо перемещать строку, которую вы еще не прочитали точку ранее в вашем сканировании.
Advice
В общем, это плохая новость, и вы должны рассмотреть READ_COMMITTED_SNAPSHOT
вместо этого - он имеет такую же выгоду позволяя читателям не блокировать писателей и наоборот, но дает вам согласованное представление данные в определенный момент времени, игнорируя все последующие изменения данных (это, однако, влияет на tempdb, поэтому обязательно проверьте его). Very thorough information here.
На самом деле, я думаю, вы могли бы прочитать все 100 не только подмножество до фиксации или откат. – Paparazzi
@Blam Не согласен. См. Мой обновленный ответ, который доказывает иначе. –
@AaronBertrand - Я думаю, вы можете быть в разных целях. Я интерпретировал замечание Блама, говоря, что *, а также * чтение (правильного) подмножества затронутых строк, вы также можете прочитать весь набор строк до того, как они будут завершены/откатны. –