
Август/Сентябрь 2003
Профессионалу администратору
Том Кайт
Корпорация Oracle
Разработка успешных приложений для СУБД Oracle
(Developing Successful Oracle Applications)
(Часть IV)
Источник: журнал Oracle Magazine, раздел "Articles online only", 2001,
/oramag/webcolumns/2001/4826_Chap01.pdf
[ От редакции "Oracle Magazine/Русское Издание":
мы продолжаем начатую в предыдущих номерах журнала публикацию
фрагментов из первой главы "Разработка успешных приложений для СУБД Oracle"
книги Тома Кайта ("Эксперт один на один с системами
баз данных Oracle") в переводе
А.П.Соколова (РДТЕХ, Протвино):
Полностью перевод книги Т.Кайта под названием "Oracle для профессионалов.
Книга 1. Архитектура и основные особенности" выпущен издательством
"ДиаСофт", которое приобрело у изд.
Wrox Press права на перевод и публикацию книги "Expert One on One: Oracle" ,
Wrox Press, 2001, ISBN 1861004826
(
http://www.wrox.com/ACON11.asp?WROXEMPTOKEN=226473Z0ingTdnhkSEinQ3g0kU&ISBN=1861004826).
Публикация в нашем журнале отрывков из первой главы "Разработка успешных приложений для СУБД Oracle"
осуществляется по согласованию и с согласия изд."ДиаСофт".]
Содержание I, II и III частей:
- Введение. “Разработка успешных приложений для СУБД Oracle”
- Мой подход
- Подход к СУБД как к “черному ящику”
- Как нужно (и как нельзя) разрабатывать приложения для СУБД Oracle
- Понимание архитектуры СУБД Oracle
- Не выполняйте длительные транзакции в среде многопотокового сервера
- Используйте переменные связывания
- Понимание управления конкурентным доступом
- Реализация механизма блокирования
- Многоверсионность
Содержание части части IV:
- *Независимость приложений от СУБД?
- *Влияние стандартов
- *Функциональные возможности и функции
Содержание последней части (V):
- Простое решение проблем
- Открытость
- Как я заставляю СУБД работать быстрее
- Отношения АБД с разработчиками
- Заключение
Разработка успешных приложений для СУБД Oracle
Независимость приложений от СУБД?
Выше я упоминал, что в разных СУБД реализация функциональных возможностей различна. С моей точки зрения создать приложение, полностью независимое от СУБД, чрезвычайно тяжело (исключая некоторые приложения, предназначенные только для чтения баз данных), а без детального понимания особенностей конкретной СУБД фактически невозможно.
Вернемся к нашему примеру с планировщиком ресурсов, рассмотренному в разделе "Реализация механизма блокирования" (перед добавлением предложения FOR UPDATE). Предположим, данное приложение было разработано в другой СУБД, в которой реализация модели блокирования и конкурентного доступа существенно отличается от СУБД Oracle. Здесь я хочу показать, что перенос приложения из среды одной СУБД в среду другой требует проверки правильности работы приложения в другой среде.
Предположим, первоначально мы разработали и внедрили приложение планирования ресурсов в СУБД, в которой используется блокирование на уровне страниц и блокирование операций чтения (читатели блокируются писателями), кроме того, был создан индекс столбцов (resource_name и start_time) таблицы SCHEDULES:
create index schedules_idx on schedules( resource_name, start_time );
Также предположим, что бизнес-правило было реализовано с помощью триггера базы данных (после выполнения оператора INSERT, но перед фиксацией транзакции мы будем проверять, что для данного временного интервала в таблице существует только одна наша строка). В системе с блокированием страниц очень вероятно, что из-за необходимости обновления индексной страницы эти транзакции будут выполняться последовательно. При вставке новых значений столбцов RESOURCE_NAME и START_TIME индексная страница блокируется (то есть блокируются все близлежащие значения этих столбцов, находящиеся в данной странице). В такой системе наше приложение, несомненно, будет работать корректно, так как наши проверки перекрытия временных интервалов будут выполняться последовательно.
Если мы перенесем это приложение в среду СУБД Oracle и просто предположим, что оно будет работать так же корректно, то мы будем поражены. В среде СУБД Oracle, в которой реализовано блокирование на уровне строк, приложение будет работать "неправильно". Как мы говорили раньше, для сериализации доступа нужно было использовать предложение FOR UPDATE. Без него два пользователя могли одновременно зарезервировать один и тот же ресурс. Это непосредственное следствие непонимания функционирования СУБД в многопользовательском режиме.
Я сталкивался с подобными проблемами столько раз, сколько приложения переносились из среды СУБД A в среду СУБД B. Когда приложение безупречно работает в СУБД A, но не работает или работает странно в СУБД B, первая мысль: СУБД B – "плохая" СУБД. Истинная правда заключается в том, что СУБД B выполняет это приложение по-другому – никакая СУБД не является неправильной или "плохой", они просто отличаются друг от друга. Знание и понимание механизмов их работы существенно помогает в разрешении подобных проблем.
Например, совсем недавно я помогал конвертировать некоторый код, написанный на языке Transact SQL (язык хранимых процедур в СУБД SQL Server) в код на языке PL/SQL. Разработчик, занимавшийся этим преобразованием, жаловался на то, что SQL-запросы в СУБД Oracle возвращают "неправильный" ответ. Запросы выглядели примерно так:
declare
l_некоторая_переменная varchar2(25);
begin
if ( некоторое_условие )
then
l_некоторая_переменная := f( … );
end if;
for x in ( select * from T where x = l_некоторая_переменная )
loop ...
Здесь нужно было найти все строки таблицы T, значение столбца X в которых равнялось значению Null, если не выполнялось "некоторое условие", или значение X равнялось конкретному значению "некоторой переменной", если "некоторое условие" выполнялось. Жалоба состояла в том, что в СУБД Oracle этот запрос не возвращал никаких данных, если не устанавливалось какое-либо конкретное значение переменной L_НЕКОТОРАЯ_ПЕРЕМЕННАЯ (то есть у нее сохранялось значение Null). В СУБД Sybase и SQL Server это было не так – запрос находил строки, значение X в которых было равно Null. Я сталкиваюсь с этим почти при каждом переносе приложений из СУБД Sybase или SQL Server в СУБД Oracle. В языке SQL подразумевается использование трехзначной логики, и в СУБД Oracle реализация значений Null соответствуют стандарту ANSI SQL. В соответствии с этим стандартом результатом сравнения X со значением Null будет не значение True ("истина") или False ("ложь"), а – неизвестное значение. Следующий фрагмент показывает, что я имею в виду:
ops$tkyte@ORA8I.WORLD> select * from dual;
D
-
X
ops$tkyte@ORA8I.WORLD> select * from dual where null=null;
no rows selected
ops$tkyte@ORA8I.WORLD> select * from dual where null<>null;
no rows selected
Если вы видите это первый раз, это может сбить с толку, – пример подтверждает, в СУБД Oracle значение Null ни равно, ни не равно значению Null. СУБД SQL Server по умолчанию так не работает: в СУБД SQL Server и Sybase значение Null равно значению Null. Ни в СУБД Oracle, ни в СУБД Sybase или SQL Server обработка операторов SQL не является неправильной – они просто отличаются друг от друга. Обе эти СУБД фактически отвечают требованиям стандарта ANSI, но тем не менее они работают по-разному. Существуют проблемы неоднозначности, обратной совместимости и т.п., которые приходится преодолевать. Например, в СУБД SQL Server поддерживается сравнение значений Null в соответствии со стандартом ANSI, но только не по умолчанию (в противном случае тысячи существующих унаследованных приложений этой СУБД не будут работать).
В данном случае одним из решений этой проблемы является замена исходного запроса на другой запрос:
select *
from t
where ( x = l_some_variable OR (x is null and l_some_variable is NULL ))
Однако это приводит к появлению другой проблемы. В СУБД SQL Server в этом запросе использовался индекс столбца Х. Но в СУБД Oracle это не так, поскольку в ней используются индексы типа B*-деревьев (более подробно о методах индексирования см. в главе 7), в которых значения Null не индексируются. Следовательно, для поиска значений Null индексы типа B*-деревьев не очень полезны.
В таком случае, чтобы минимизировать влияние на код, мы можем присвоить Х значение, которое никогда не встретится в действительности. Здесь значение Х по определению должно быть положительным числом, поэтому мы выбираем число, равное –1. Таким образом, запрос становится следующим:
select * from t where nvl(x,-1) = nvl(l_some_variable,-1)
И мы создаем индекс на базе функции (function-based index):
create index t_idx on t( nvl(x,-1) );
С минимальными изменениями мы достигаем того же конечного результата. Из вышеизложенного важно понимать следующее:
- СУБД отличаются друг от друга. Опыт работы с одной из них может быть частично использован в другой, но вы должны быть готовы к каким-то существенным различиям так же, как и к некоторым незначительным различиям;
- незначительные различия (такие, как обработка значений Nulls) могут влиять на значительные различия (такие, как механизм управления конкурентным доступом);
- единственный путь решения таких проблем – знать СУБД: и как она работает, и как реализованы ее функциональные возможности.
Разработчики часто спрашивают меня (обычно более одного раза в день), как сделать что-то в среде конкретной СУБД. Например, они задают вопрос: "Как создать временную таблицу в хранимой процедуре?" Я прямо не отвечаю на подобные вопросы, а задаю вопрос: "Почему вы хотите сделать это?" Много раз ответ был следующим: "В СУБД SQL Server мы создавали временные таблицы в наших хранимых процедурах, нам нужно сделать то же самое в СУБД Oracle." Этот ответ я и ожидал. В таком случае я отвечаю просто: "Вам не нужно создавать временные таблицы в хранимых процедурах СУБД Oracle (вы только думаете, что это нужно сделать)." Фактически, делать это в СУБД Oracle не рекомендуется, в противном случае вы обнаружите, что:
- выполнение операций DDL препятствует масштабируемости;
- операции DDL выполняются медленно;
- при выполнении операции DDL ваша транзакция фиксируется;
- для доступа к таким таблицам необходимо использовать динамический SQL, а не статический;
- динамический SQL в PL/SQL выполняется не так быстро или оптимизируется не так хорошо, как статический SQL.
Практический результат: вам не нужно делать точно то же самое, что вы делали в СУБД SQL Server (если даже вам нужны временные таблицы в СУБД Oracle). В СУБД Oracle нужно делать то, что наилучшим образом подходит для СУБД Oracle. То же самое можно сказать про перенос приложений из СУБД Oracle в СУБД SQL Server, в которой не нужно создавать одну таблицу для совместного хранения временных данных всеми пользователями (именно так это делается в СУБД Oracle). В противном случае будут ограничиваться масштабируемость и конкурентный доступ.
Влияние стандартов
Если все СУБД соответствуют стандарту SQL92, они должны быть одинаковыми. По крайней мере, такое предположение делалось неоднократно. В данном разделе я хочу развеять этот миф.
SQL92 – стандарт ANSI/ISO для СУБД. Он является преемником стандарта SQL89. Стандарт определяет язык (SQL) и поведение (транзакции, уровни изоляции и т.д.), которые определяют поведение СУБД. Знаете ли вы, сколько СУБД, доступных коммерчески, соответствуют стандарту SQL92? Знаете ли вы, что это мало что означает в вопросах мобильности запросов и приложений?
Начиная знакомство со стандартом SQL92, мы обнаружим, что стандарт имеет четыре уровня:
- начальный уровень
(Entry-level) – уровень, который реализован большинством производителей СУБД. Имеет небольшие усовершенствования по сравнению с предыдущим стандартом SQL89. Никто из производителей СУБД не имеет сертификатов более высокого уровня; фактически, Национальный институт стандартов и технологий (NIST, National Institute of Standards and Technology), ответственный за сертификацию на соответствие стандарту, даже не проводил никакой сертификации на соответствие более высоким уровням стандарта. Я входил в рабочую группу, которая в 1993 году занималась сертификацией СУБД Oracle 7.0 на соответствие начальному уровню стандарта SQL92. Набор функциональных возможностей СУБД Oracle 7.0 соответствует начальному уровню стандарта;
- переходный
(Transitional) – функциональные возможности этого уровня находятся где-то между возможностями начального уровня и промежуточного;
- промежуточный
(Intermediate) – добавлено много функциональных возможностей включая (приведен неполный список возможностей):
- динамический SQL,
- каскадные операции удаления (DELETE), обеспечивающие сохранение ссылочной целостности,
- типы данных DATE (дата) и TIME (время),
- домены,
- символьные строки переменной длины,
- выражения CASE (оператор выбора),
- функции CAST (функции приведения типов данных),
- полный
(Full) – добавлены средства обеспечения (список возможностей также неполный):
- управления соединениями,
- строкового типа данных BIT (бит),
- откладываемых ограничений целостности (Deferrable integrity constraints),
- производных таблиц в предложениях FROM,
- подзапросов в предложениях CHECK,
- временных таблиц.
В начальный уровень стандарта не включены такие функциональные возможности, как внешние соединения, новый синтаксис внутренних соединений и т.д. В переходном уровне специфицирован синтаксис внешних и внутренних соединений. В промежуточном уровне появились дополнительные функциональные возможности, а в полный уровень, естественно, вошел весь стандарт SQL92. В большинстве книг о стандарте SQL92 не рассматриваются различия между этими уровнями, что приводит к путанице. В таких книгах демонстрируется теоретическая реализация СУБД в соответствии с полным уровнем стандарта SQL92, что делает невозможным их практическое применение в каких-либо СУБД, соответствующих стандарту SQL92. Например, в СУБД SQL Server синтаксис "внутренних соединений" поддерживается в операторах SQL, а в СУБД Oracle не поддерживается. Но обе СУБД соответствуют стандарту SQL92. Вы можете выполнять внутренние и внешние соединения в СУБД Oracle, но по-другому, чем это делается в СУБД SQL Server. Практический результат: СУБД не так далеко "ушли" он начального уровня стандарта SQL92, поэтому если вы используете средства промежуточного или более высокого уровней, вы рискуете потерей возможности простого переноса вашего приложения в среду других СУБД.
Не бойтесь использовать специфические функциональные возможности, реализованные производителем СУБД, – в конце концов, вы платили за них большие деньги. Каждая СУБД имеет свой собственный "набор хитрых приемов", и вы всегда в любой СУБД сможете найти способ выполнения операции. Используйте все лучшее в вашей текущей СУБД, а при переходе в другую СУБД перепишите подобные компоненты. Для выделения таких изменений используйте хорошие методы программирования. Такие же методы применяются разработчиками переносимых приложений ОС. Цель: использовать все доступные средства, но обеспечить возможность изменения реализации в зависимости от конкретной ситуации.
Конкретный пример. Общая функция во многих приложениях СУБД – генерация уникального ключа для каждой строки. Когда вы вставляете строку, СУБД должна для вас автоматически сгенерировать ключ. В СУБД Oracle для этого реализован объект базы данных SEQUENCE (последовательность). В СУБД Informix – тип данных SERIAL (порядковый). В СУБД Sybase и SQL Server – тип данных IDENTITY (идентичность). В каждой СУБД – свой метод генерации ключей. Эти методы отличаются как способами их использования, так и возможными результатами. Таким образом, для хорошо осведомленного разработчика существует два пути, по которым он может следовать:
- разработка способа генерации уникальных ключей, полностью независимого от конкретных СУБД;
- приспосабливание к различным реализациям и использование различных методов генерации ключей в каждой СУБД.
Теоретически достоинство первого подхода заключается в том, что вы сможете переносить свое приложение из среды одной СУБД в среду другой без каких-либо изменений. Я называю этот подход "теоретическим", так как "контраргументы" такой реализации настолько велики, что такое решение становится совершенно неосуществимым. Если вы собираетесь разработать процесс, полностью независимый от конкретных СУБД, вы должны создать таблицу типа:
create table id_table ( id_name varchar(30), id_value number );
insert into id_table values ( ‘MY_KEY’, 0 );
Затем для получения нового значения ключа вы должны будете выполнить:
update id_table set id_value = id_value + 1 where id_name = ‘MY_KEY’;
select id_value from id_table where id_name = ‘MY_KEY’;
Выглядит достаточно просто, но в результате такой реализации пользователи смогут выполнять транзакции только по очереди. Для увеличения значения счетчика нам нужно обновить данную строку, а это приведет к сериализации этой операции в нашей программе. В лучшем случае только один пользователь в данный момент времени сможет сгенерировать новое значение этого ключа. Проблема заключается в том, что наша транзакция может быть намного более продолжительной, чем это представлено выше. Операторы UPDATE и SELECT в нашем примере – только два оператора из множества других операторов, которые потенциально могут выполняться в нашей транзакции после генерации нового значения ключа. Такая сериализация будет существенно ограничивать масштабирование. Представьте себе использование этого метода в веб-сайтах, обрабатывающих заказы, для генерации номера каждого заказа.
Корректный подход к решению этой проблемы заключается в использовании лучших методов в каждой СУБД. В СУБД Oracle это выглядит так (предположим, необходимо генерировать значения первичного ключа таблицы T):
create table t ( pk number primary key, ... );
create sequence t_seq;
create trigger t_trigger before insert on t for each row
begin
select t_seq.nextval into :new.pk from dual;
end;
Здесь каждой вставляемой строке автоматически (и незаметно для пользователей) назначается уникальный ключ. Аналогичные результаты могут быть получены и в других СУБД с помощью средств, реализованных в них, – синтаксис операторов создания таблиц будет другим, но конечные результаты будут такими же. Мы стремимся использовать средства каждой СУБД для генерации неблокируемого уникального ключа в условиях интенсивного конкурентного доступа, и здесь мы фактически не изменяем приложение – в данном случае вся логика реализована операторами DDL.
Другой пример "безопасного программирования", учитывающий требования мобильности программного обеспечения, – реализация многоуровневого доступа к базе данных, когда это требуется (если вы понимаете, что в каждой СУБД функциональные средства реализованы по-разному). Рассмотрим программирование с использованием интерфейса JDBC (Java DataBase Connectivity – средство организации доступа Java-приложений к базам данных). Если вы используете обычные операторы SQL:
SELECT, INSERT, UPDATE и DELETE), вероятно, вам не нужны уровни абстракции. Вы можете вставить операторы SQL непосредственно в приложение, если синтаксис используемых операторов поддерживается каждой СУБД, в которой вы собираетесь развернуть ваше приложение. Другой подход, обеспечивающий повышение как уровня мобильности приложений, так и производительности, – использование хранимых процедур, возвращающих результирующие множества (resultsets). Вы обнаружите, что в каждой СУБД хранимые процедуры могут возвращать результирующие множества, но способы реализации этого различны. Реальный исходный код, который вы должны написать, будет разным в различных СУБД.
Итак, у вас есть два варианта: либо использовать хранимые процедуры, возвращающие результирующие множества, либо разрабатывать разный код для различных СУБД. Я предпочитаю следовать принципу "разный код для различных производителей". Кажется, что такой подход приводит к увеличению времени реализации приложения в разных СУБД. Однако реально вы обнаружите, что при этом подходе проще разрабатывать приложения для разных СУБД. Вместо поиска безупречных операторов SQL, которые работают во всех СУБД (возможно, в одних лучше, чем в других), вы будете использовать операторы SQL, которые лучше всего работают в данной СУБД. Вы можете делать это за пределами самого приложения, тем самым повышая гибкость настройки приложения. Вы можете исправлять медленно работающие запросы в самой СУБД, без модификации приложения. Кроме того, вы можете воспользоваться всеми преимуществами использования расширений языка SQL, сделанных данным производителем. Например, в СУБД Oracle поддерживаются иерархические запросы (с помощью предложения CONNECT BY). Эта уникальная возможность имеет большое значение при реализации рекурсивных запросов. В СУБД Oracle вы можете свободно пользоваться этим расширением языка SQL, поскольку оно реализовано "за пределами" приложений (скрыто в СУБД). В других СУБД для получения такого же результата вам, возможно, придется использовать временные таблицы и хранимые процедуры. Вы платили за такие возможности, так что можете пользоваться ими.
Аналогичные методы используют разработчики программного обеспечения для различных платформ. Корпорация Oracle, например, использует такие методы в своих разработках СУБД. Большой объем кода (небольшой процент кода всей СУБД), называемого OSD-кодом (Operating System Dependent – зависимый от операционной системы), специально разрабатывается для каждой платформы. Этот уровень абстракции позволяет использовать в СУБД Oracle многие собственные функциональные возможности конкретных ОС, обеспечивающие производительность и интеграцию. Тот факт, что СУБД Oracle может работать в ОС Windows как многопотоковое приложение, а в ОС UNIX как мультипроцессное приложение, подтверждает это. Механизмы взаимодействия процессов выносятся на такой уровень абстракции, который может быть переработан с учетом особенностей конкретной ОС, обеспечивая возможность подготовки существенно различающихся реализаций. Эти реализации выполняются как приложения, разработанные непосредственно и специально для данной платформы.
В дополнение к синтаксическим различиям в операторах SQL, различиям в реализациях и различиям в производительности выполнения одних и тех же запросов в разных СУБД, кратко рассмотренных выше, существуют проблемы конкурентного доступа, уровней изоляции транзакций, согласованности запросов и т.д. Более подробно эти вопросы мы рассмотрим в главе 3, "Блокирование и конкурентность", и в главе 4, "Транзакции". Стандарт SQL92 пытается дать непосредственные определения того, как должны работать транзакции, как должны быть реализованы уровни изоляции, но в конечном счете вы получите различные результаты в разных СУБД. Все это обуславливается реализацией. Для переноса приложения в другие СУБД требуются большие усилия, даже если вы на 100 процентов соблюдаете стандарт.
Функциональные возможности
Вам необязательно стремиться к "независимости от СУБД" – вы должны точно понимать, что предлагается в вашей конкретной СУБД, и в полной мере пользоваться этим. В этом разделе не рассматриваются все функциональные возможности, предлагаемые в СУБД Oracle 8i. Само по себе их описание может составить очень толстую книгу. В комплекте документации по СУБД Oracle 8i описание только новых функциональных средств занимает отдельную книгу. Около 10 000 страниц документации, поставляемой с СУБД Oracle, посвящено описанию каждой функциональной возможности. В этом же разделе вы сможете получить по крайней мере поверхностное представление о том, что предлагается в СУБД Oracle .
Как я упоминал раньше, я отвечаю на вопросы о СУБД Oracle, задаваемые в Вебе. Я говорил, что 80 процентов моих ответов – просто ссылки на документацию. Пользователи спрашивают, как написать какие-то сложные фрагменты кода, используя функциональные средства СУБД (или за пределами ее). Я только показываю им фрагмент документации, описывающий уже готовую реализацию этой логики в СУБД Oracle и правила ее использования. Это позволяет быстро получать ответы. Мне задают вопрос: "Я хочу где-нибудь сохранять копию своих данных. Я хочу, чтобы это была копия только для чтения. Мне нужно обновлять ее только один раз в сутки, в полночь. Как мне написать для этого код?" Ответ простой: оператор CREATE SNAPSHOT (создать моментальную копию данных). Это и есть функциональное средство, встроенное в СУБД.
Верно, вы можете написать собственную процедуру тиражирования данных, вы даже можете сделать это ради забавы, но в конце рабочего дня заниматься этим не очень разумно. Вообще говоря, СУБД может сделать это лучше вас. Тиражирование, например, реализовано в ядре СУБД, написанном на языке C. Оно быстро работает, достаточно просто в использовании и надежно. Оно работает в разных версиях на разных платформах. Оно поддерживается, поэтому если вы столкнетесь с проблемами, группа поддержки корпорации Oracle рада будет помочь вам. Если вы перейдете на новую версию СУБД, тиражирование будет поддерживаться по-прежнему, возможно, с какими-то новыми функциональными возможностями. Теперь рассмотрим вариант, который вы могли бы разработать сами. Вы должны обеспечить его поддержку во всех версиях СУБД, которые вам нужно поддерживать. Совместимость СУБД версий 7.3, и 8.0, и 8.1, и 9.0 и т.д. – вот что будет вашей заботой. Если произойдет сбой, вы не сможете обратиться к группе поддержки. Если выйдет новая версия СУБД Oracle, вы должны будете перенести свою процедуру тиражирования в эту версию.
Отсутствие полного представления о доступных средствах может долгое время давать о себе знать. Недавно я беседовал с некоторыми разработчиками и их руководителями. Они показали мне фрагмент программного обеспечения, разработанный ими. Это была система, ориентированная на обработку сообщений и предназначенная для решения проблемы организации очередей в СУБД. Это обычное явление, когда много пользователей использует таблицу базы данных как "очередь". Вы хотите, чтобы пользователи могли блокировать следующую запись в очереди, пропускать ранее заблокированные записи (уже обработанные)? Проблема, с который вы здесь сталкиваетесь, заключается в том, что в СУБД синтаксис операций пропуска заблокированных строк не документирован. Так, если вы ничего не знаете о функциональных возможностях СУБД Oracle, вы можете предположить, что если вам требуется программное обеспечение для организации очередей, функционирующее над СУБД, то вы должны будете разработать его.
Это и сделали разработчики. Они создали ряд процессов и разработали API (Application Programming Interface – интерфейс прикладного программирования) для организации очередей сообщений. Они затратили на это значительное количество человеко-часов и были уверены, что создали уникальное средство. Сразу же, как только мне показали его и рассказали о функциональных возможностях, мне оставалось только сказать: "Advanced Queues" – средства организации очередей в СУБД Oracle. Это собственные средства СУБД. Они решают проблему "получения первой незаблокированной строки в таблице очередей и блокирования ее". Но разработчики, не зная о существовании такой возможности, затратили массу времени и энергии на разработку собственных средств. Кроме затрат в прошлом, они будут тратить массу времени на сопровождение в будущем. Их руководитель был больше чем поражен, узнав, что уникальный фрагмент программного обеспечения на самом деле имитирует собственные средства СУБД.
Я встречал пользователей СУБД Oracle 8i, которые для чтения сообщений из программных каналов (pipes) создают daemon-процессы (прим. пер. скрытая от пользователя служебная программа, вызываемая при выполнении какой-либо функции). Эти процессы выполняют операторы SQL, находящиеся в читаемом сообщении, и фиксируют свою транзакцию. Это делалось для аудита транзакций, результаты которого не должны пропасть в случае отката большой транзакции. Обычно, если для аудита доступа к некоторым данным используются триггеры или что-то подобное, в случае последующего сбоя какого-то оператора вся работа откатывается назад (в главе 4, "Транзакции", мы более подробно обсудим атомарность на уровне операторов). Итак, послав сообщение в другой процесс, разработчики обеспечивали выполнение отдельной транзакции, которая фиксировалась после выполнения операций аудита. Запись аудита сохранялась, если даже выполнялся откат родительской транзакции. В версиях СУБД Oracle до версии Oracle 8i это был подходящий (и почти единственный) способ реализации такой возможности. Я рассказал им о функциональной возможности СУБД, называемой автономными транзакциями (более подробно обсудим их в главе 15). Автономные транзакции, реализуемые одной строкой кода, позволяют выполнять точно то, что они делают. Это означает, что они могли избавиться от большей части своего кода и не сопровождать его. Кроме того, повышается общая производительность системы и упрощается ее понимание.
Приведенные выше примеры -
не что иное, как ответ на часто задаваемые мне вопросы: большие сложные проблемы уже решены в самой СУБД. Если вы не найдете время для изучения доступных возможностей, вы будете обречены иногда решать их сами.
Окончание следует
|