Read Committed vs Read Uncommited, если обе транзакции не откатываются

Я пытаюсь понять уровни изоляции read commited и read uncommitted. Я знаю, что теоретическое чтение без фиксации допускает грязное чтение, а чтение с фиксацией — нет, но я до сих пор не могу понять.

этот пример

Учитывая рисунок выше, если ни одна из транзакций не была прервана, то окончательный результат будет одинаковым как для чтения зафиксированного, так и для незафиксированного чтения?


person user1264    schedule 06.01.2019    source источник
comment
Привет и добро пожаловать в StackOverflow. Никто не собирается перепечатывать ваш код, поэтому изображение помогает понять порядок, но, пожалуйста, предоставьте его также в виде текста.   -  person Angel M.    schedule 06.01.2019
comment
здесь нечего переписывать, наглядное пособие прекрасное и понятное, а код просто для пояснений в контексте. конечно, будет лучше, если OP будет включать таблицу уценки.   -  person Derviş Kayımbaşıoğlu    schedule 06.01.2019
comment
Операторы модификации данных получают блокировки как на зафиксированном чтении, так и на незафиксированном уровне изоляции. Таким образом, результаты будут одинаковыми в вашем примере.   -  person Dan Guzman    schedule 06.01.2019


Ответы (4)


Если вы работаете с зафиксированным уровнем изоляции чтения, T2 должен дождаться на шаге 4, пока T1 завершит и зафиксирует свою работу. кроме того, T1 на шаге 6 не может найти Nome с Maria%, поэтому удаляет 0 строк.

но на уровне изоляции незафиксированного чтения обе операции чтения/записи могут выполняться одновременно.

Результат Для уровня изоляции read commited:

Pessoas (Jaoa Silva, 96.....)
Pessoas (Maria Fon..., 9199...)
Pessoas (Joao Manuel Silva, 9699...)

тогда как для чтения незафиксированного уровня изоляции

Pessoas (Joao Manuel Silva, 9699...)
person Derviş Kayımbaşıoğlu    schedule 06.01.2019

Ваш пример не имеет ничего общего с Isolation Levels. Это потому, что они влияют на поведение readers, а не writers, а в вашем примере есть только writers.

Вам следует обратиться к этой статье BOL: Понимание уровней изоляции, в котором говорится

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

В вашем примере ни одна из транзакций read, они обе modify. Первая транзакция получит X для заинтересованных RID или key (зависит от структуры таблицы, если это куча или кластеризованная таблица) -- в будущем я буду называть ее res_1 -- для вставки и удерживать ее на все время транзакции (у него также будет IX на соответствующих page и object), и то же самое для первого оператора второй транзакции: он получит X на res_2 при вставке.

При попытке DELETE вторая транзакция будет заблокирована, так как она не может получить X (или U в случае отсутствия индекса по условию where), потому что на том же ресурсе уже есть X (res_1) удерживаться первой транзакцией. И второго INSERT во второй транзакции не будет, потому что предыдущий DELETE заблокирован.

Наконец, когда первая транзакция делает попытку своего DELETE, ей нужно X или U (в зависимости от наличия индекса) на res_2, но она уже заблокирована с X tran2, поэтому она также заблокирована и выхода из этой ситуации нет, каждая сессия ждет еще один сеанс для завершения, и ни один сеанс не может быть завершен, в этот момент происходит deadlock, и сервер разрешает его rolling back одной из транзакций.

person sepupic    schedule 07.01.2019

READ UNCOMMITTED позволяет читать грязные данные, которые не были зафиксированы другими транзакциями. Механизм SQL Server игнорирует любую блокировку читаемой таблицы и считывает данные непосредственно из памяти.

READ COMMITTED прочитает данные, которые уже были COMMITTED, но будет ждать, если на данные влияет другая транзакция.

Таким образом, в приведенном примере система не только читает, но и пытается УДАЛИТЬ строку, которая еще не была СОВЕРШЕНА, поэтому оба будут ждать завершения другой транзакции, поэтому пример является типичным примером для DEADLOCK.

Чтобы проиллюстрировать разницу между COMMITTED и UNCOMMITTED, я покажу вам простой и понятный пример, который мы запустим дважды в двух режимах.

-- Query Window 1
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;  -- Prepare for first Run
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;    -- Prepare for second Run

BEGIN TRANSACTION                                   -- Step 1
INSERT INTO Audit (ProductID, PrevValue, NewValue, ChangedBy)   
    VALUES (1, 'AAA', 'aaa', SYSTEM_USER);          -- Step 3
COMMIT TRANSACTION                                  -- Step 5

-- Query Window 2
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;  -- Prepare for first Run
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;    -- Prepare for second Run

BEGIN TRANSACTION                           -- Step 2
SELECT * FROM Audit WHERE PrevValue = 'AAA' -- Step 4
COMMIT TRANSACTION                          -- Step 6

Мы должны запустить сначала строку для UNCOMMITTED LEVEL в обоих запросах, а затем перейти к первому, выполнить шаг 1, перейти ко второму, шагу 2 и так далее. В UNCOMMITTED, когда мы запускаем шаг 4, мы сразу же увидим результаты, поскольку мы делаем грязное чтение (из памяти). Для второго запуска мы сначала удалим тест строки с помощью:

DELETE FROM Audit WHERE PrevValue LIKE 'AAA';   

Затем запустит строку для COMMITTED LEVEL в обоих окнах запроса и запустит ту же последовательность. Мы увидим, что теперь, когда мы запускаем Шаг 4, система остается без ответа. Как раз в тот момент, когда мы запускаем шаг 5, чтобы зафиксировать вставку, окно покажет результаты.

Я надеюсь, что теперь вопрос стал более ясным.

person Angel M.    schedule 06.01.2019
comment
Незафиксированные и в памяти — совсем не одно и то же. Вполне возможно, что незафиксированные данные будут записаны на диск в контрольных точках или зафиксированные данные будут считаны из памяти. - person Martin Smith; 07.01.2019
comment
Я не сказал, что это одно и то же... Я просто имею в виду, что для приведенного примера оба имеют тот же эффект, что и DEADLOCK. В любом случае, спасибо за комментарий, я уточню свой ответ... - person Angel M.; 08.01.2019

Найдите ссылку https://www.postgresql.org/docs/9.5/transaction-iso.html

я переписываю

13.2.1. Чтение зафиксированного уровня изоляции

Read Committed — это уровень изоляции по умолчанию в PostgreSQL. Когда транзакция использует этот уровень изоляции, запрос SELECT (без предложения FOR UPDATE/SHARE) видит только данные, зафиксированные до начала запроса; он никогда не видит ни незафиксированные данные, ни изменения, зафиксированные во время выполнения запроса параллельными транзакциями. По сути, запрос SELECT видит моментальный снимок базы данных на момент начала выполнения запроса. Однако SELECT видит результаты предыдущих обновлений, выполненных в рамках его собственной транзакции, даже если они еще не зафиксированы. Также обратите внимание, что две последовательные команды SELECT могут видеть разные данные, даже если они находятся в одной транзакции, если другие транзакции фиксируют изменения после запуска первой SELECT и до начала второй SELECT.

Команды UPDATE, DELETE, SELECT FOR UPDATE и SELECT FOR SHARE ведут себя так же, как SELECT с точки зрения поиска целевых строк: они находят только целевые строки, которые были зафиксированы на момент запуска команды. Однако такая целевая строка может быть уже обновлена ​​(или удалена, или заблокирована) другой параллельной транзакцией к моменту ее обнаружения. В этом случае предполагаемый модуль обновления будет ждать фиксации или отката первой транзакции обновления (если она все еще выполняется). Если первый модуль обновления откатывается, то его результаты сводятся на нет, и второй модуль обновления может продолжить обновление первоначально найденной строки. Если первый модуль обновления зафиксирует, второй модуль обновления проигнорирует строку, если первый модуль обновления удалил ее, в противном случае он попытается применить свою операцию к обновленной версии строки. Условие поиска команды (предложение WHERE) повторно оценивается, чтобы увидеть, соответствует ли обновленная версия строки условию поиска. Если это так, второй модуль обновления продолжает свою работу, используя обновленную версию строки. В случае SELECT FOR UPDATE и SELECT FOR SHARE это означает, что обновленная версия строки блокируется и возвращается клиенту.

person sankar banerjee    schedule 13.07.2019