ALLOW_SNAPSHOT_ISOLATION и READ_COMMITTED_SNAPSHOT

38

Большинство форумов и примеров в Интернете всегда предлагают включить оба варианта ALLOW_SNAPSHOT_ISOLATIONи READ_COMMITTED_SNAPSHOTвключить их, когда кто-то задает моментальный снимок, версию строки или аналогичный вопрос.

Я думаю, слово SNAPSHOT в обоих случаях немного сбивает с толку. Я подумал, что для того, чтобы ядро ​​базы данных использовало управление версиями строк вместо блокировок для поведения по умолчанию READ_COMMITTED, база данных READ_COMMITTED_SNAPSHOTустановлена ​​на ON независимо от того, какой ALLOW_SNAPSHOT_ISOLATIONпараметр.

Параметр ALLOW_SNAPSHOT_ISOLATIONустановлен на ON только для обеспечения изоляции моментального снимка при запуске транзакции (например, SET SNAPSHOT УРОВНЯ ИЗОЛЯЦИИ ТРАНЗАКЦИИ) независимо от READ_COMMITTED_SNAPSHOTнастройки.

Единственная причина, по которой эти два параметра должны быть установлены в положение «ВКЛ», - это когда им нужно иметь READ COMMITTED для версий строк и изоляции моментальных снимков.

Мой вопрос, является ли мое понимание неверным в некотором роде? И что эти два параметра всегда должны быть включены в ON (особенно для READ COMMITTED для версий строк)?

Travis
источник

Ответы:

25

Ваше понимание верно. Это немного сбивает с толку.

Ким Трипп (один из программистов SQL Server и неотъемлемая часть SQLSkills) в точности повторяет то, что вы заявили в видеороликах MCM об изоляции моментальных снимков . Перейдите к 41:45 в видео, чтобы перейти к той части, где она отвечает на ваш вопрос.

Если вы используете, ALLOW_SNAPSHOT_ISOLATIONубедитесь, что вы используете SET TRANSACTION ISOLATION LEVEL SNAPSHOTв своем коде, в противном случае вы не получите никаких преимуществ.

Если вы установите SET READ_COMMITTED_SNAPSHOT ON, то нет необходимости изменять какой-либо код. MS SQL Server автоматически применяет изоляцию моментальных снимков для этой таблицы.

Я не проверял, чтобы увидеть, что произойдет, если вы попросите другой уровень изоляции в вашем коде, я подозреваю, что он перезапишет эту опцию, но сначала протестируйте ее.

Быстрый взгляд на снижение производительности с помощью Snapshot Isolation.

Хорошая статья о том, как изоляция моментальных снимков может изменить ожидаемое поведение вашего приложения . Здесь показаны примеры того, как оператор обновления и оператор выбора могут возвращать совершенно разные и неожиданные результаты.

Али Разеги
источник
Спасибо за ссылку. Как и другие BOL, она обсуждала эти два параметра независимо и коллективно (вот где это немного сбивает с толку, или, может быть, я слишком много думаю об этом). Я должен был проверить это, чтобы получить лучшее понимание.
Трэвис
4
Это отличный ответ, и я хотел бы уточнить только пару пунктов. Во-первых, если вы просто сканируете видео, начните с 23:18, а также с 41:45. Раннее время добавляет больше деталей. Хотя Ким упоминает ответ на исходный вопрос, все равно необходимо изменить код при использовании обоих. Read_Committed_Snapshot - это изоляция на уровне оператора, другими словами, применяется только к оператору, выполняемому в данный момент. Allow_Snapshot_Isolation - это изоляция на уровне транзакций, все между Begin Tran и Commit. Они могут быть задействованы отдельно, но для каждой строки установлены одинаковые 14-байтовые служебные данные.
Delux
Благодарим Вас за добавление дополнительной информации об устанавливаемой 14-байтовой служебной информации. Ким проходит через это в видео, но очень полезно иметь это здесь и в тексте.
Али Разеги
15

ОК, вернулся домой и проверил. Вот наблюдение.

CREATE DATABASE TEST;
GO
CREATE TABLE TABLE1
(
    ID tinyint,
    Details varchar(10)
);
GO
INSERT INTO TABLE1
VALUES (1, 'Original');
GO

SELECT
    name,
    snapshot_isolation_state_desc,
    is_read_committed_snapshot_on
FROM sys.databases
WHERE name = 'TEST';
GO

Первый тест с обоими настройками подтвержден как выключенный.

Запрос 1

USE TEST;

BEGIN TRAN
UPDATE TABLE1
SET Details = 'Update'
WHERE ID = 1;

--COMMIT;
--ROLLBACK;
GO

Запрос 2

USE TEST;

SELECT ID, Details
FROM TABLE1
WHERE ID = 1;
GO

В этом тесте запрос 2 ожидает подтверждения запроса 1, DMV dm_tran_locks показывает, что исключительная блокировка для TABLE1 возникла в результате запроса 1.

USE TEST;

SELECT
    DB_NAME(tl.resource_database_id) AS DBName,
    resource_type,
    OBJECT_NAME(resource_associated_entity_id) AS tbl_name,
    request_mode,
    request_status,
    request_session_id
FROM sys.dm_tran_locks tl
WHERE 
    resource_database_id = db_id('TEST')
    AND resource_type = 'OBJECT'

Во втором тесте , откат предыдущей транзакции, установите READ_COMMITTED_SNAPSHOT на ON, но оставьте ALLOW_SNAPSHOT_ISOLATION OFF.

ALTER DATABASE TEST
SET READ_COMMITTED_SNAPSHOT ON
WITH ROLLBACK IMMEDIATE;
GO

Запустите запрос 1 и запустите запрос 2. DMV показывает запрос 1 с эксклюзивной блокировкой, но запрос 2 возвращает детали с параметром «Оригинал» без запроса 1, фиксирующего транзакцию. Похоже, что версия READ_COMMITTED строки на месте.

При добавлении SET TRANSACTION ISOLATION LEVEL SNAPSHOT;запроса 1 и запроса 2 и выполнении запроса 1 или запроса 2 возвращается ошибка - транзакция изоляции моментального снимка не смогла получить доступ к базе данных «TEST», поскольку изоляция моментального снимка не разрешена в этой базе данных. Используйте ALTER DATABASE, чтобы разрешить изоляцию снимка.

Третий тест , откат предыдущей транзакции. Установите READ_COMMITTED_SNAPSHOT OFF и ALLOW_SNAPSHOT_ISOLATION ON.

ALTER DATABASE TEST
SET READ_COMMITTED_SNAPSHOT OFF
WITH ROLLBACK IMMEDIATE;
GO

ALTER DATABASE TEST
SET ALLOW_SNAPSHOT_ISOLATION ON;
GO

Запустите запрос 1, а затем запрос 2. DMV показывает исключительную блокировку, вызванную запросом 1. Похоже, что запрос 2 ожидает завершения запроса 1. Включение ALLOW_SNAPSHOT_ISOLATION ON, по-видимому, не позволяет READ COMMITTED версионирование строк.

Добавление SET TRANSACTION ISOLATION LEVEL SNAPSHOT;как к запросу 1, так и к запросу 2. Запустите запрос 1, а затем запрос 2. В то время как DMV показывает, что запрос 1 подвергается эксклюзивной блокировке, запрос 2 возвращает детали с параметром «Оригинал». Снимок изоляции, кажется, на месте.

Наблюдение из теста показывает, что READ_COMMITTED_SNAPSHOTсам по себе включает / отключает версию чтения READ COMMITTED независимо от ALLOW_SNAPSHOT_ISOLATIONнастроек, и наоборот.

Travis
источник
4

Ваше понимание верно. Мне нравится краткое, чистое и простое определение отсюда :

Когда опция базы данных READ_COMMITTED_SNAPSHOT включена, транзакции, устанавливающие уровень изоляции зафиксированного чтения, используют управление версиями строк.

Когда опция базы данных ALLOW_SNAPSHOT_ISOLATION включена, транзакции могут устанавливать уровень изоляции моментального снимка.

Похоже, много недоразумений исходит от самой MS. Например, здесь они говорят:

Если для параметра базы данных READ_COMMITTED_SNAPSHOT задано значение ON, ядро ​​базы данных по умолчанию использует управление версиями строк и изоляцию моментальных снимков вместо использования блокировок для защиты данных.

Но упомянутая «изоляция моментального снимка» не равна поведению транзакции, для которой set transaction isolation level snapshotприменяется.

Что касается разницы, хорошее объяснение здесь .

Возможно, было бы лучше, если бы READ_COMMITTED_SNAPSHOT было названо READ_COMMITTED_ROW_VERSIONING или что-то в этом роде. :)

OV
источник
0

Мне нравится это резюме от Microsoft :

Установка опции READ_COMMITTED_SNAPSHOT ON разрешает доступ к версионным строкам с уровнем изоляции READ COMMITTED по умолчанию. Если для параметра READ_COMMITTED_SNAPSHOT установлено значение OFF, необходимо явно установить уровень изоляции моментального снимка для каждого сеанса, чтобы получить доступ к версионным строкам.

flam3
источник