|
Программирование >> Программирование баз данных
на то, что откат выполнен в связи с ошибкой 1205. Выполнение других транзакций продолжается как обычно (и фактически посторонний свидетель не сможет узнать о том, что произведен откат одной из транзакций, иначе как по возникшему замедлению). Способы определения наличия взаимоблокировок в СУБД SQL Server Через каждые пять секунд в СУБД SQL Server проверяются все текущие транзакции для определения того, освобождение каких блокировок требуется для их дальнейшего вьшолнения, тогда как сами эти транзакции еще не получили возможность установить данные блокировки. По существу, в ходе этой проверки регистрируется информация о том, какие существующие потребности в ресурсах еще не удовлетворены. А во время проведения следующей проверки состояния вьшолнения всех требований о предоставлении блокировок в СУБД предпринимается попытка выяснить, имеются ли еще не удовлетворенные требования, которые были обнаружены во время предыдущей проверки. В случае обнаружения таких требований осуществляется рекурсивная проверка всех открытых транзакций в целях обнаружения циклической цепочки требований на предоставление блокировок. Если такая цепочка обнаруживается, это означает, что имеет место взаимоблокировка; в таком случае одна из транзакций выбирается в качестве жертвы взаимоблокировки и осуществляется ее откат. Способы выбора жертв взаимоблокировки По умолчанию выбор жертвы взаимоблокировки осуществляется с учетом расхода ресурсов в каждой из затронутых транзакций. Операция отката применяется к той транзакции, в ходе вьшолнения которой был израсходован наименьший объем ресурсов (благодаря этому обеспечивается осуществление в СУБД SQL Server наименьшего объема работы при повторном выполнении всех операций восстанавливаемой транзакции). Разработчик имеет возможность в определенной степени повлиять на то, как осуществляется выбор жертвы взаимоблокировки, с использованием параметра DEADLOCK PRIORITY, устанавливаемого в СУБД SQL Server с помощью оператора SET, но обычно не рекомендуется брать на себя такую ответственность, поэтому информация по данной теме выходит за рамки рассмотрения настоящей книги. Предотвращение возникновения взаимоблокировок Если система эксплуатируется достаточно интенсивно, то в ней невозможно полностью избежать возникновения взаимоблокировок, но на практике вполне осуществима задача почти полного их устранения. Иными словами, некоторые методы позволяют добиться того, чтобы взаимоблокировки почти не оказывали влияния на функционирование системы. Ниже приведены простые правила (но иногда требующие значительных усилий), которые позволяют сократить или даже устранить взаимоблокировки. Во всех операциях доступ к объектам должен осуществляться в одном и том же порядке. Применяемые транзакции должны быть как можно более короткими, а операторы транзакций должны оформляться в виде одного пакета. Следует использовать наиболее низкий необходимый уровень изоляции транзакции из всех возможных. В той же транзакции, в которой осуществляется обработка данных, не следует допускать возникновения перерывов, время окончания которых не регламентируется (например, из-за взаимодействия с пользователем, перехода от одного пакета к другому и т.д.). В управляемой среде необходимо использовать связанные соединения. Почти каждый раз, когда приходится сталкиваться с проблемами взаимоблокировки, обнаруживается нарушение по меньшей мере одного (а обычно даже большего количества) из этих правил. Ниже каждая из этих рекомендаций рассматривается более подробно. Осуществление доступа к объектам во всех операциях в одном и том же порядке Выше перечислены правила предотвращения взаимоблокировок, которые, по мнению автора, являются наиболее важными, но прежде всего необходимо обеспечить, чтобы доступ к объектам во всех операциях обработки данных всегда происходил в одном и том же порядке. Замечательная особенность этого правила заключается в том, что его соблюдение не требует почти никаких издержек; достаточно неизменно придерживаться его в своей работе. На самых ранних этапах процесса проектирования необходимо принять решение о том, как должен осуществляться доступ к объектам базы данных, включая определение самой последовательности доступа, а после этого достаточно соблюдать привычный подход при написании кода каждого запроса, процедуры или триггера, создаваемого для данного проекта. Суть приведенной рекомендации вполне очевидна - если проблема заключается в том, что с базой данных установлены два соединения и в каждом из этих соединений вьщвигается требование на получение тех же ресурсов, что и в другом соединении, то нужно сделать вывод, что теперь уже поздно заниматься решением указанной проблемы. Рассмотрим простой пример. Предположим, что имеются две таблицы: Suppliers и Products. А теперь допустим, что в базе данных реализованы два процесса, в которых используются обе эти таблицы. В процессе 1 происходит прием информации, касающейся пополнения товарных запасов, данные таблицы Products обновляются с учетом поступления нового количества товаров, а затем обновления вносятся в таблицу Suppliers с учетом данных о суммарном количестве приобретенньгх товаров. С другой стороны, в процессе 2 регист рируется информация о сбыте; при этом вносится корректировка, затрагивающая суммарное количество проданных товаров, показанное в таблице Suppliers, после чего сокращение количества товарных запасов регистрируется в таблице Products. Если оба эти процесса осуществляются параллельно, то нарушения в работе становятся неизбежными. Процесс 1 захватывает исключительную блокировку на таблице Products. Процесс 2 захватывает исключительную блокировку на таблице Suppliers. После этого в процессе 1 предпринимается попытка установить блокировку на таблице Suppliers, но процесс 1 вынужден перейти в состояние ожидания до того времени, как процесс 2 освободит свою существующую блокировку. Между тем в процессе 2 предпринимается попытка создать блокировку на таблице Products, но в нем приходится ожидать, пока процесс 1 освободит свою существующую блокировку. Возникает тупиковая ситуация, в которой оба процесса ожидают друг друга. После обнаружения такой ситуации в СУБД SQL Server приходится выбирать жертву взаимоблокировки. Но в этом сценарии порядок действий можно изменить так, чтобы в процессе 2 вначале уменьшалось количество товарных запасов в таблице Products и только после этого обновлялось общее количество проданных товаров в таблице Suppliers. Такая организация работы функционально эквивалентна первому способу организации взаимодействия процессов, причем для перехода к этой новой форме организации взаимодействия процессов не требуется никаких затрат. Тем не менее результат становится буквально поразительным, поскольку взаимоблокировки полностью исключаются (во всяком случае, между двумя этими процессами). Ниже приведен краткий обзор действий, происходящих при такой организации работы. Если оба указанных процесса эксплуатируются одновременно, то в процессе 1 приобретается исключительная блокировка на таблице Products (до сих пор все остается неизменным). Затем в процессе 2 также предпринимается попытка установить блокировку на таблице Products, но этот процесс вынужден ожидать завершения работы с этой таблицей в процессе 1 (обратите внимание на то, что какие-либо действия с таблицей Suppliers еще не были выполнены). Процесс 1 завершает работу с таблицей Products, но не освобождает блокировку, поскольку транзакция еще не закончена. Процесс 2 продолжает ожидать освобождения блокировки, установленной на таблице Products. На следующем этапе процесс 1 приступает к получению блокировки на таблице Suppliers. Процесс 2 продолжает ожидать освобождения блокировки, которая установлена на таблице Products. Процесс 1 завершает свою работу с таблицей Products и выполняет фиксацию или откат транзакции, в зависимости от обстоятельств, но в любом случае освобождает все блокировки. С этого времени процесс 2 получает возможность установить блокировку на таблице Products и осуществляет остальную часть транзакции без каких-либо дополнительных затруднений. Итак, достаточно было изменить порядок доступа к таблицам в указанных двух запросах, и это позволило устранить потенциальную проблему возникновения взаимоблокировки. По возможности придерживайтесь этой рекомендации по соблюдению единой последовательности доступа к таблицам, что даст возможность намного успешнее справляться с взаимоблокировками. Применение как можно более коротких транзакций, реализованных в виде одного пакета Эта рекомендация относится к числу наиболее важных. Кроме того, у опытных разработчиков стремление к соблюдению такой рекомендации становится почти инстинктивным- они просто применяют ее на практике, не задумываясь над тем, что так действительно следует делать. Мало того, если предыдущая рекомендация требовала осуществления хоть каких-либо действий, соблюдение данной рекомендации вообще не требует никаких усилий. Достаточно предусмотреть вьшолнение в транзакции лишь самых необходимых операций и исключить все остальное - нет ничего проще. Причины, по которым сокращение объема операций, выполняемых в транзакции, оказывает положительный эффект, являются вполне очевидными - чем больше времени занимает транзакция и чем больше объектов она затрагивает (в ходе выполнения предусмотренных в ней операций), тем выше вероятность того, что придется столкнуться с тем, что в каком-то другом процессе потребуется один или несколько из используемых в транзакции объектов (т.е. степень распараллеливания уменьшится). Если же транзакция остается
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |