Проблема несогласованных данных 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Проблема несогласованных данных



На рис. 12.6 изображена еще одна схема работы программы для обработки заказов. Джо снова начинает принимать от своего клиента заказ на 100 изделий ACI-41004. Вскоре после этого Мэри начинает со своим клиентом разговор об этих же изделиях, и ее программа выясняет их количество на складе. Затем клиент начинает расспрашивать Мэри об изделиях ACJ-41005, и программа Мэри выполняет запрос о наличии этих изделий. Тем временем клиент Джо решает заказать изделия ACI-41004, поэтому его программа обновляет соответствующую строку и выполняет инструкцию commit, завершая транзакцию по приему заказа. После некоторых размышлений клиент Мэри решает заказать изделия ACI-41004, которые Мэри предлагала ему вначале. Ее программа вновь запрашивает информацию об изделиях ACI-41004, но новый запрос показывает, что в наличии имеется только 39 изделий вместо 139, показанных предыдущим запросом несколько секунд тому назад.

 

Рисунок 12.6 – проблема несогласованных данных

 

В данном примере, в отличие от двух предыдущих, состояние базы данных правильно отражает реальную ситуацию. В наличии осталось только 39 изделий ACI- 41004, поскольку клиент заказал у Джо 100 штук. Из-за того что Мэри увидела промежуточные данные программы Джо, ничего особенного не произошло — заказ от Джо был успешно принят. Однако с точки зрения программы Мэри, база данных не была целостной в течение выполняемой ею транзакции. В начале транзакции некоторая строка содержала одни данные, а позднее в той же самой транзакции она содержала другие данные, поскольку «внешние события» нарушили целостное восприятие базы данных этой программой. Такая несогласованность может привести к различным проблемам даже в том случае, если программа Мэри не будет обновлять базу данных, опираясь на результаты первого запроса. Например, если ее программа накапливает итоговые суммы или собирает статистические данные, то нет гарантии, что она отражает информацию правильно. В этом примере проблема заключается в том, что программа Мэри имела доступ к результатам обновления, выполненного программой Джо для строки, которую программа Мэри уже извлекала ранее. В стандарте SQL2 эта проблема обозначена как «Р2», или проблема «нестабильных результатов выборки». Программа Мэри не смогла дважды выполнить один и тот же запрос и при этом получить одинаковые результаты.

 

Проблема строк-призраков

 

На рис. 12.7 еще раз изображена схема работы программы для обработки заказов. На этот раз менеджер по продажам запустил программу генерации отчетов, которая просматривает таблицу ORDERSи печатает список заказов от клиентов Билла Адамса, подсчитывая их итоговую сумму. Тем временем Биллу звонит клиент и делает допол­нительный заказ на $5000. Заказ добавляется в базу данных, и транзакция заверша­ется. Вскоре после этого программа менеджера по продажам снова просматривает таблицу orders,выполняя тот же запрос, что и прежде. На этот раз в таблице имеется дополнительный заказ, а итоговая сумма заказов на $5000 больше, чем в результате первого запроса.

Здесь, как и в предыдущем примере, проблема заключается в несогласованности данных. Состояние базы данных соответствует реальной ситуации, и целостность данных не нарушена, но один и тот же запрос, выполненный дважды в течение одной транзакции, возвращает два различных результата. В предыдущем примере запрос извлекал одну строку и противоречивость данных была вызвана выполнением инст­рукции update. Выполнение инструкции deleteмогло бы вызвать ту же проблему. В примере, представленном на рис. 12.7, проблема возникла в результате выполнения инструкции insert. В первом запросе дополнительной строки не было, и после выполнения второго запроса сложилось такое впечатление, что она появилась из ниоткуда, как призрак. Проблема строк-призраков, как и проблема несогласованных данных, может привести к противоречивым и неправильным расчетам. В стандарте SQL2 эта проблема обозначена как «РЗ».

 

Рисунок 12.7 – Проблема строк – призраков

 

Параллельные транзакции

 

Как видно из приведенных примеров, при обновлении базы данных в многопользовательском режиме существует возможность нарушения ее целостности. Чтобы исключить такую возможность, в SQL используется механизм транзакций. Помимо того что реляционная СУБД обязана выполнять транзакции по принципу «либо все, либо ничего», она имеет и другое обязательство по отношению к транзакциям:

 

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

 

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

 

«Когда две транзакции, див, выполняются параллельно, СУБД гарантирует, что результаты их выполнения будут точно такими же, как и в случае, если’ (а) вначале выполняется транзакция А, а затем транзакция в; или (б) вначале выполняется транзакция в, а затем транзакция а».

 

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

Однако тот факт, что СУБД изолирует пользователя от действий других пользователей, не означает, что о них можно забыть. Совсем наоборот. Поскольку другим пользователям также требуется обновлять базу данных параллельно с вами, ваши транзакции должны быть как можно более простыми и короткими, чтобы объем работы, выполняемой всеми, был больше.

Предположим, например, что вы запускаете программу, последовательно выполняющую три больших запроса на выборку. Так как программа не обновляет базу данных, может показаться, что нет необходимости думать о транзакциях и не требуется использовать инструкцию COMMIT.Однако на самом деле программа должна выполнять эту инструкцию после каждого запроса Почему? Вспомним, что транзакция начинается автоматически вместе с первой инструкцией SQL в программе. Без инструкции COMMITтранзакция будет продолжаться до окончания программы. Кроме того, СУБД гарантирует, что данные, извлекаемые в течение транзакции, будут непротиворечивыми и не будут зависеть от транзакций других пользователей. Это означает, что если ваша программа извлекла из базы данных определенную строку, то ни один пользователь, кроме вас, не сможет изменить эту строку до окончания вашей транзакции. Так происходит из-за того, что позднее в этой же транзакции вы можете снова извлечь ту же строку, а СУБД должна гарантировать, что в этой строке будут содержаться те же данные, что и при первой выборке. Поэтому по мере того как ваша программа будет последовательно выполнять три запроса, другие пользователи не смогут изменять все большее количество данных.

Мораль этого примера проста: при написании программ для промышленных реляционных баз данных всегда необходимо думать о транзакциях. Транзакции должны быть как можно короче. «Используйте инструкцию COMMITраньше и чаще», — это хороший совет для всех, кто работает с программным SQL.

Практическая реализация строгой модели многопользовательских транзакций может привести к существенному замедлению работы с базами данных, насчитывающими сотни и тысячи пользователей. Кроме того, логика работы многих приложений вовсе не требует полной изоляции пользователей, которая подразумевается описанной моделью. Например, разработчик приложения может точно знать, что программа генерации отчетов никогда не запрашивает повторно одну и ту же строку таблицы в течение одной транзакции. В этом случае проблема несогласованных данных просто не может возникнуть. Или, допустим, разработчик может знать, что приложение обращается к некоторым таблицам базы данных только для выборки. Если бы иметь возможность сообщить подобного рода сведения СУБД, это позволило бы устранить многие проблемы, связанные с производительностью при обработке транзакций.

В стандарте SQL1 вопросы производительности не рассматривались, поэтому в большинстве СУБД были реализованы собственные схемы повышения производительности транзакций. В стандарте SQL2 описана новая инструкция set transaction,назначение которой заключается в том, чтобы указать СУБД, какую степень изоляции следует обеспечить при обработке транзакций. Применять эту инструкцию нет необходимости, если для вашего приложения вопросы обработки транзакций не играютроли или сами транзакции достаточно просты

Чтобы понять особенности работы инструкции set transaction,нужно разобраться с методикой блокировки, применяемой в коммерческих СУБД для обеспечения параллельного выполнения транзакций. В оставшейся части главы подробно рассматриваются тонкости механизма блокировки и способы повышения производительности транзакций, описанные в стандарте SQL2 и реализованные в различных СУБД.

 

Блокировка *

Практически во всех ведущих СУБД для обработки параллельных транзакций применяется довольно сложный механизм блокировки. Однако принципы блокировки транзакций довольно просты. На рис. 12.8 изображена схема простой блокировки, устраняющей конфликты между двумя параллельными транзакциями.

 

Рисунок 12.8 – Блокировка при одновременном выполнении двух транзакций

 

Когда транзакция А обращается к базе данных, СУБД автоматически блокирует все части базы данных, в которых транзакция осуществляет выборку или изменение. Транзакция В выполняется параллельно, и СУБД также блокирует те части базы данных, к которым она обращается. Если транзакция В обращается к той части базы данных, которая заблокирована транзакцией А, то СУБД приостанавливает выполнение транзакции в, заставляя ее ждать до тех пор, пока данные не будут разблокированы. СУБД снимает блокировку, вызванную транзакцией А,только после того, как в этой транзакции встретится инструкция COMMIT или rollback. Затем СУБД позволяет продолжить выполнение транзакции В. Теперь транзакция В блокирует эту же часть базы данных, защищая ее от других транзакций.

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

 

Уровни блокировки

В базе данных блокировка может быть реализована на различных уровнях. Самой грубой формой блокировки является блокировка всей базы данных. Этот вид блокировки легко реализовать, но при этом в каждый момент времени можно будет выполнять только одну транзакцию. Если транзакция затрачивает некоторое время «на размышления» (например, время обсуждения заказа с клиентом), то доступ всех остальных пользователей к базе данных будет при этом заблокирован, что приводит к слишком низкой производительности.

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

Во многих СУБД реализована блокировка на уровне страниц. В этом случае СУБД блокирует отдельные блоки данных на диске («страницы»), когда транзакция обращается к мим. Остальным транзакциям запрещается доступ к заблокированным страницам, но они могут обращаться к другим страницам данных (и блокировать их для себя). Обычно используются страницы размером 2, 4 и 16 Кб. Поскольку большая таблица состоит из сотен или даже тысяч страниц, две транзакции, обращающиеся к двум различным строкам таблицы, как правило, обращаются к различным страницам; в результате обе транзакции выполняются параллельно.

За последние несколько лет в большинстве ведущих СУБД была реализована блокировка на уровне строк. Она допускает параллельное выполнение транзакций, которые обращаются к двум различным строкам таблицы, даже если эти строки содержатся на одной странице. Хотя такая возможность кажется несущественной, в случае таблиц, содержащих небольшое число строк (например, таблица OFFICES из учебной базы данных), она может играть важную роль. Блокировка на уровне строк обеспечивает параллельное выполнение большого количества транзакций. К сожалению, осуществить блокировку строк различной длины гораздо сложнее, чем блокировку страниц фиксированного размера, поэтому повышение параллелизма работы обеспечивается за счет усложнения логики блокирования и роста накладных расходов. Тем не менее, поставщики СУБД, которые делают упор на оперативную обработку транзакций, все более широко применяют такой режим блокировки. Часто имеется возможность выбора типа блокировки- на уровне страниц или на уровне строк.

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

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

 



Поделиться:


Последнее изменение этой страницы: 2021-05-27; просмотров: 129; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.144.254.231 (0.016 с.)