SQL - статьи

       

Механизм блокировок


В большинстве SQL-продуктов изолированность реализована на основе механизма блокировок. Поэтому полезно описать уровни изолированности ANSI SQL в терминах блокировок, хотя при этом возникают некоторые проблемы.

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

Предикатная блокировка по чтению (записи) множества элементов данных, определяемого задаваемым условием <search condition>, фактически блокирует все элементы данных, удовлетворяющие этому условию. Это множество элементов данных теоретически является бесконечным, поскольку включает все элементы данных, уже присутствующие в базе данных и удовлетворяющие условию <search condition>, и также все фантомные элементы данных, которых еще нет в базе данных, но которые будут удовлетворять условию <search condition>, если попадут в нее вследствие выполнения операции вставки или модификации. В терминах SQL предикатная блокировка покрывает все присутствующие в базе данных элементы, которые удовлетворяют предикату, и любые другие элементы, которые могут быть стать удовлетворяющими этому предикату в результате выполнения операторов INSERT, UPDATE, or DELETE. Две предикатных блокировки разных транзакций конфликтуют, если хотя бы одна из них является блокировкой по записи и имеются (возможно, фантомные) элементы данных, покрываемые обеими блокировками. Блокировка элемента данных (блокировка записи (record)) – это предикативная блокировка, в которой предикат именуюет данную запись.

Транзакция обладает правильно построенными (well-formed writes) записями (чтениями), если она запрашивает блокировку по записи (чтению) каждого элемента данных или предиката перед выполнением операции записи (чтения) этого элемента данных или множества элементов данных, определяемого предикатов. Транзакция называется правильно построенной (well-formed), если правильно построены все ее операции записи и чтения. Транзакция обладает двухфазными (two-phase writes) записями (чтениями), если она не устанавливает новую блокировку по записи (чтению) на элемент данных после снятия с него блокировки по записи (чтению). Транзакция осуществляет двухфазное блокирование (two-phase locking), если она не запрашивает новeю блокировку (по записи или чтению) после снятия какой-либо блокировки.


Блокировка, запрашиваемая транзакцией, называется долговременной (long duration), если она не снимается до конца транзакции (фиксации или аварийного завершения). В противном случае блокировка называется кратковременной (short duration). На практике кратковременные блокировки обычно снимаются сразу же после завершения операции.

Если одна транзакция удерживает блокировку, а другая транзакция запрашивает установку конфликтующей блокировки, то этот запрос не удовлетворяется до тех пор, пока конфликтующая блокировка первой транзакции не будет освобождена.

Фундаментальная теорема сериализуемости гласит, что правильно построенное двухфазное блокирование гарантирует сериализуемость – каждая история, порождаемая двухфазным блокированием, эквивалентна некоторой последовательной истории. Наоборот, если транзакция не является правильно построенной или не осуществляет двухфазное блокирование, то возможны несериализуемые истории выполнения [EGLT]. Исключения составляют только вырожденные случаи.

В стремлении показать эквивалентность блокировок, зависимостей и формализмов, основанных на аномалиях, в статье [GLPT] определялись четыре степени согласованности (degrees of consistency). Определения аномалий (см. определение 1) были слишком расплывчатыми. Авторов этой статьи продолжают критиковать за этот аспект определений (см. также [GR]). Испытание временем смогли выдержать только более строгие математические определения в терминах историй, графов зависимостей и блокировок.

Таблица 2. Степени согласованности и блокировочные уровни изоляции, опреляемы в терминах блокировок

Уровень согласованности

= Блокировочный уровень



изолированности


Блокировки по чтению на

элементах данных и предикатах

(одинаковы, если нет замечаний
)

Блокировки по записи на

элементах данных и предикатах

(везде одинаковы)


Степень 0

Ничего не требуется

Правильно построенные записи

Степень 1 = блокировочное

чтение незафиксированных данных

(Locking READ UNCOMMllTED)

Ничего не требуется

Правильно построенные записи

Долговременные блокировки по записи

Степень 2 = Блокировочное

чтение зафиксированных данных

(Locking READ COMMITTED)

Правильно построенные чтения

Кратковременные блокировки по чтению

(в обоих случаях)

Правильно построенные записи

Долговременные блокировки по записи

Устойчивость курсора (см. разд. 4.1)

(Cursor Stability)

Правильно построенные чтения

Блокировка по чтению удерживается

на текущем элементе курсора

Кратковременные предикатные

блокировки по чтению

Правильно построенные записи

Долговременные блокировки по записи

Блокировочное

повторимое чтение

(Locking REPEATABLE READ)

Правильно построенные чтения

Долговременные блокировки по чтению

на элементах данных

Кратковременные предикатные

блокировки по чтению

Правильно построенные записи

Долговременные блокировки по записи

Степень 3 = Блокировочная

сериализуемость

(Locking SERIALIZABLE)

Правильно построенные чтения

Долговременные блокировки по чтению

(в обоих случаях)

Правильно построенные записи

Долговременные блокировки по записи

<


Во таблице 2 определяется несколько типов изолированности в следующих терминах: области действия блокировок (элементы или предикаты), режимы (по чтению или по записи) и продолжительность (кратковременные или долговременные). Мы полагаем, что блокировочные уровни изолированности, называемые блокировочным чтением незафиксированных данных (Locking READ UNCOMMITTED), блокировочным чтением зафиксированных данных (Locking READ COMMITTED), блокировочным повторимым чтением (Locking REPEATABLE READ) и блокировочной сериализуемостью (Locking SERIALIZABLE), подразумевались в определениях уровней изолированности ANSI SQL, но, как демонстрируется позже в этой статье, они существенно отличаются от тех, которые перечислены в . Следовательно, необходимо различать уровни изолированности, определяемые в терминах блокировок, и уровни изолированности ANSI SQL, определяемые с помощью феноменов. Поэтому названия уровней изолированности в имеют префикс "Блокировочные", а в – "ANSI".

В [GLPT] определяется согласованность Степени 0, на которой разрешаются грязное чтение и запись (Dirty Reads and Writes). Требуется только атомарность операций. Степени 1, 2 и 3 аналогичны Locking READ UNCOMMITTED, Locking READ COMMITTED и Locking SERIALIZABLE соответственно. Ни одна степень согласованности не соответствует уровню изолированности Locking REPEATABLE READ.

Дейт и IBM [DAT, DB2] поначалу использовали термин "повторимые чтения" (Repeatable Reads) для обозначения сериализуемости или блокировочной сериализуемости. Этот термин кажется более понятным, чем термин "третья степень изолированности" [GLPT], хотя по значению они идентичны. Значение термина ANSI SQL REPEATABLE READ отличается от значения оригинального определения, данного Дэйтом, и мы полагаем, что принятая в ANSI SQL терминология является неудачной. Поскольку аномалия P3 специальным образом не исключается на уровне изолированности ANSI SQL REPEATABLE READ, из определения P3 ясно, что чтения НЕ являются повторимыми! В мы продолжаем неправильно использовать этот термин в Locking REPEATABLE READ, чтобы соответствовать определению ANSI. Аналогично, Дейт ввел термин "устойчивость курсора" (Cursor Stability) как более понятное название для второй степени изолированности с дополнительной защитой от потерянных изменений через курсор, как объясняется ниже в подразделе 4.1 ниже.



Определение. Уровень изолированности L1 слабее (weaker) уровня изолированности L2 (или L2 сильнее (stronger), чем L1; обозначим это как L1 << L2), если все несериализуемые истории, удовлетворяющие критериям уровня L2, также удовлетворяют критериям уровня L1, и существует хотя бы одна несериализуемая история, возможная на уровне L1 и невозможная на уровне L2. Два уровня изолированности L1 и L2 эквивалентны (equivalent), что обозначается как L1 == L2, если множества допустимых несериализуемых историй на уровнях L1 и L2 идентичны. L1 не сильнее (no stronger), L2, что обозначается как L1 << L2, если L1 << L2 или L1 == L2. Два уровня изолированности несравнимы (incomparable), что обозначается как L1 >><< L2, когда каждый уровень изолированности допускает несериализуемую историю, недопустимую на другом уровне.

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

Эти определения приводят к слудующему замечанию.

Замечание 1.

Locking READ UNCOMMITTED << Locking READ COMMITTED << Locking REPEATABLE READ << Locking SERIALIZABLE

В следующем разделе мы сравним определения ANSI с блокировочными определениями.


Содержание раздела