Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
лабы / dbaBook.pdf
Скачиваний:
441
Добавлен:
26.04.2015
Размер:
3.89 Mб
Скачать

FROM A, B

WHERE (A.X1 = B.X1) AND … AND (A.Xn = B.Xn)

6.5. Программный (встроенный) SQL

Программный (встроенный) SQL (Embedded SQL) предназначен для того, чтобы встраивать SQL запросы в прикладную программу. Представьте себе, что Вы – программист, разрабатывающий приложение для работы с базами данных. Совершенно, очевидно, что для Вас является неприемлемой интерактивная форма работы. Вместо этого, Вам необходимо каким-то образом встроить SQL-запросы в программу, написанную, скажем на языке C++. Но как это сделать?

Как объяснить компилятору C++, что часть Вашей программы это не операторы C++, а операторы какого-то SQL?

Как соединить возможности языка программирования высокого уровня (переменные, ветвления, циклы) и возможности SQL (запросы на языке, близком к естественному, где уже не на программиста, а на СУБД ложится труд по их оптимизации и выбору плана выполнения)?

Эти и некоторые другие проблемы решаются несколькими способами. Эти способы частично описаны и в стандарте SQL-92. На настоящий момент используются 3 варианта программного SQL: статический, динамический и основанный на различных API. Посмотрим, что представляет собой каждый вариант.

6.5.1. Статический SQL

Статический SQL – разновидность программного SQL, предназначенная для встраивания SQL-операторов в текст программы на языке программирования высокого уровня.

Рассмотрим еще раз алгоритм выполнения SQL-запросов в интерактивном режиме работы. Легко видеть, что пользователь вынужден ожидать результатов выполнения запроса в течение всего времени работы алгоритма. Если через некоторое время пользователю снова нужно будет выполнить тот же самый запрос, СУБД вновь проделает те же самые действия, что и при предыдущем обращении. Налицо некоторое несовершенство механизма:

одни и те же этапы выполняются каждый раз заново для одинаковых запросов; СУБД не может обрабатывать интерактивные запросы с опережением.

176

Решение подобных проблем очевидно – часть действий по обработке запроса необходимо выполнять один раз, сохранять результат в некотором виде, а потом использовать столько раз, сколько необходимо. Эта идея является одной из основных идей программного SQL. Итак, программный, а в частности и статический SQL позволяет:

использовать операторы интерактивного SQL в тексте программы на языке программирования высокого уровня;

наряду с операторами интерактивного SQL использовать новые специальные конструкции, дополняющие SQL и увеличивающие его возможности; для передачи параметров в запрос использовать в тексте запроса

переменные, объявленные в программе; для возврата в программу результатов запроса использовать спе-

циальные конструкции, отсутствующие в интерактивном SQL; осуществлять компиляцию запросов совместно с программой, обеспечивая в последствии согласованную работу программы и СУБД. Заранее (на этапе компиляции) выполнять действия по анализу и оптимизации запросов, экономя время, затрачиваемое на этапе выполнения программы.

Рассмотрим два основных этапа, связанных с работой статического SQL, – компиляция программы и работа (выполнение) программы.

Схема компиляции и сборки программы выглядит следующим образом:

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

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

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

177

эти объектные модули вместе с библиотеками СУБД собираются в один исполняемый модуль – приложение.

Наряду с этими операциями происходит работа с файлом, содержащим SQL-инструкции. В литературе этот модуль часто носит название «модуль запросов к базе данных» (Database Request Module, DBRM) [8]. Обработку этого модуля осуществляет специальная утилита, которая обычно носит название BIND. Для каждой инструкции SQL утилита выполняет следующие действия:

осуществляет синтаксический анализ запроса (проверяет, является ли запрос корректным);

проверяет, существуют ли в базе данных те объекты, на которые ссылается запрос;

выбирает, каким образом осуществлять выполнение запроса –

план выполнения запроса; Все планы выполнения запросов сохраняются в СУБД для последующего использования.

Программа на ЯПВУ с включением инструкций SQL

 

 

 

 

 

Препроцессор

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Исходный файл

 

 

 

Модуль запросов

 

с заменой инструкций СУБД

 

 

к базе данных

 

на вызовы функций СУБД

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Утилита BIND

 

Компилятор

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Объектный файл

 

 

Объектный файл

 

 

Анализ синтаксиса

 

 

 

библиотеки СУБД

 

 

Проверка наличия

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

объектов

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Компоновщик

 

 

 

 

 

 

Оптимизация

 

 

 

 

 

 

 

(выбор плана)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Исполняемый файл

 

 

 

 

 

СУБД

 

 

 

 

 

 

 

 

 

 

 

(сохранение плана в БД)

178

Рис. 50. Схема компиляции программы со встроенными инструкциями статического SQL

Исполняемый модуль (запуск на выполнение)

Выполнение обычных

 

 

Вызов функций СУБД

 

 

для выполнения инструкций

инструкций ЯПВУ

 

 

 

 

встроенного SQL

 

 

 

 

 

 

 

 

 

 

 

 

 

Поиск плана выполнения

 

 

 

запроса в БД

 

 

 

Выполнение запроса

 

 

 

Отправка результатов

 

 

 

в приложение

 

 

 

 

 

 

Рис. 51. Схема выполнения программы со встроенными инструкциями статического SQL

Схема выполнения программы выглядит следующим образом: Программа запускается на выполнение обычным образом.

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

СУБД выполняет запрос в соответствии с выбранным планом. Результат выполнения запроса поступает в приложение.

Основными командами статического SQL являются:

EXEC SQL

спецификатор, указывающий, что

 

следующая за ним инструкция явля-

 

ется инструкцией встроенного SQL

;

в языке C – признак окончания инст-

 

рукции встроенного SQL

DECLARE TABLE

объявляет таблицу, которая потом

 

будет использоваться в инструкциях

 

встроенного SQL

SQLCODE

переменная для обработки ошибок

SQLSTATE

переменная для обработки ошибок

 

179

GET DIAGNOSTICS

инструкция для обработки ошибок

WHENEVER

набор совместно используемых инст-

SQLERROR

рукций для упрощения

обработки

SQLWARNING

ошибок

 

NOT FOUND

 

 

GOTO

 

 

CONTINUE

 

 

BEGIN DECLARE SECTION

инструкции для определения области,

END DECLARE SECTION

в которой будут объявлены перемен-

 

ные, в последствии используемые в

 

запросах SQL

 

INTO

используется в операторе SELECT

 

для указания переменной, в которую

 

необходимо поместить результат вы-

 

полнения запроса

 

 

 

 

DECLARE CURSOR

Курсор – специальный

инструмент,

 

предназначенный для обработки ре-

 

зультатов запроса, содержащих более

 

одной строки. Работа с курсором по-

 

хожа на работу с файлами.

 

Данная инструкция служит для соз-

 

дания курсора и связывания его с

 

конкретным запросом.

 

OPEN

Команда, открывающая курсор и по-

 

буждающая СУБД начать выполне-

 

ние запроса. Устанавливает курсор

 

перед первой строкой результата.

FETCH

Команда, перемещающая указатель

 

текущей строки (курсор) на следую-

 

щую строку. В некоторых СУБД и

 

стандарте SQL-92 реализованы раз-

 

ные формы команды FETCH, пере-

 

мещающие курсор на произвольную

 

строку результатов запроса.

CLOSE

Закрывает курсор и прекращает дос-

180

туп к результатам запроса

Использование описанной выше схемы компиляции/сборки/выполнения программы позволяет:

использовать SQL совместно с программой на языке программирования высокого уровня; заранее осуществлять проверку синтаксиса запросов и оптимиза-

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

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

При использовании статического варианта вложенного (программного) SQL необходимо на этапе написания программы точно знать состав запросов, которые необходимо будет выполнять в программе.

Во многих случаях это ограничение является существенным. Для его устранения была введена новая разновидность программного SQL – динамический SQL. Рассмотрим кратко основные идеи динамического SQL.

6.5.2. Динамический SQL

Динамический SQL – разновидность программного SQL, предназначенная для встраивания SQL-операторов в текст программы на языке программирования высокого уровня, допускающая динамическое формирование и выполнение запросов во время работы программы.

История возникновения динамического SQL во многом связана с компанией IBM, внедрившей этот мощный инструмент в свою СУБД DB2. Стандарты SQL, в частности, SQL-1 не поддерживали динамический SQL. Лишь в 1992 году в стандарт SQL-2 были включены спецификации динамического SQL. Для того, чтобы использовать этот инструментарий в своих программах, необходимо представлять основные концепции, основные идеи, заложенные в динамический SQL и

181

принципы его функционирования. Именно это и является предметом рассмотрения в данном разделе.

Теоретики считают основной концепцией динамического SQL следующее утверждение: встроенная инструкция SQL не записывается в исходный текст программы. Вместо этого программа формирует текст инструкции во время выполнения в одной из своих областей данных, а затем передает сформированную инструкцию в СУБД для динамического выполнения [8].

Вспомним, как работал статический SQL: схема использования подразумевала 2 этапа – компиляция программы и выполнение программы. При этом на этап компиляции ложилась основная нагрузка в том смысле, что он решал вопросы проверки, разбора и оптимизации запросов, поскольку было известно, что именно разбирать и оптимизировать. Совершенно очевидно, что подобную двухэтапную схему нельзя реализовать для динамического SQL, ведь на этапе компиляции программы еще неизвестно, что именно нужно разбирать и оптимизировать.

Каковы последствия этого изменения? Любой механизм имеет свои достоинства и недостатки.

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

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

Рассмотрим схему функционирования динамического SQL. Схема предусматривает одноэтапное и двухэтапное выполнение инструкций.

Одноэтапное выполнение инструкций осуществляется командой

EXECUTE IMMEDIATE.

182

Исполняемый модуль (запуск на выполнение)

Выполнение обычных инструкций ЯПВУ

Команда

EXECUTE IMMEDIATE

Вызов функций СУБД для выполнения инструкций встроенного SQL

Анализ синтаксиса

Проверка наличия объектов

Оптимизация (выбор плана) Выполнение плана

Рис. 52. Схема выполнения программы со встроенными инструкциями динамического SQL с применением одноэтапной схемы

Схема выполнения инструкции подразумевает:

динамическое формирование команды SQL в строковом виде во время работы программы; передача строкового вида инструкции в СУБД при помощи ко-

манды EXECUTE IMMEDIATE;

выполнение инструкции системой управления БД, включающее синтаксический анализ, проверку параметров, оптимизацию (выбор плана) и выполнение этого плана.

Основные проблемы одноэтапной схемы заключаются в том, что она не позволяет выполнять инструкции SELECT (ибо нет средств для возврата в приложение результатов запроса) и приводит к нерациональному расходованию вычислительных ресурсов (т.к. при повторном выполнении той же инструкции вновь будет затрачено время на все те же действия по ее интерпретации и выполнению).

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

183

Исполняемый модуль (запуск на выполнение)

Выполнение обычных

Вызов функций СУБД для

выполнения инструкций

инструкций ЯПВУ

встроенного SQL

 

Команда

Анализ синтаксиса

Проверка параметров

PREPARE

Оптимизация (выбор плана)

 

 

Подстановка параметров

Команда

Выполнение плана

EXECUTE

Возврат результата в

 

приложение

Рис. 53. Схема выполнения программы со встроенными инструкциями динамического SQL с применением двухэтапной схемы

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

На этапе выполнения СУБД подставляет значения параметров (полученные из программы) и использует сформированный ранее план выполнения для достижения результата.

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

Основными командами динамического SQL являются:

 

EXECUTE IMMEDIATE

Немедленное выполнение инструкции

 

PREPARE

Подготовка инструкции к выполнению

 

EXECUTE

Выполнение подготовленной ранее инст-

 

 

рукции

 

DESCRIBE

Специальная команда, участвующая при

 

 

возврате результата выполнения инструк-

184

 

 

ций динамического SQL.

DECLARE CURSOR

Разновидность инструкции DECLARE

 

CURSOR, применявшейся ранее в рамках

 

статического SQL, содержащая вместо

 

запроса его имя (связанное с запросом

 

при помощи инструкции PREPARE).

OPEN

Разновидности инструкций для работы с

FETCH

курсором в динамическом SQL.

CLOSE

 

6.6. Интерфейсы программирования приложений (API). DB-Library, ODBC, OCI, JDBC

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

Наряду с описанным выше механизмом существует и активно применяется еще один подход, связанный с наличием специальных

API (application programming interface – интерфейс программирования приложений). Эти API представляют собой библиотеки функций, разработанные для обеспечения связи прикладной программы с СУБД посредством выполнения SQL-запросов. Прикладная программа вызывает специальные функции библиотеки для передачи в СУБД SQLзапроса в текстовом виде и для получения результатов выполнения запросов, а также различной служебной информации.

Применение подобного подхода приводит к тому, что программистам более не требуется изучать специальные наборы инструкций SQL, а необходимо лишь изучить специальную библиотеку функций. С учетом того, что механизм использования API является широко используемым и стандартным подходом (чего только стоит использование мощного аппарата Windows API), для специалистов нет ничего

185

нового в изучении еще одной библиотеки, в данном случае – для общения с СУБД.

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

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

Посмотрим, как работают прикладные программы, использующие различные API. Как можно заметить, принцип работы от одной библиотеки к другой не претерпевает принципиальных изменений. Схема работы приложения совместно с SQL API выглядит следующим обра-

зом [8]:

программа получает доступ к базе данных путем вызова одной или нескольких API-функций, подключающих программу к СУБД и к конкретной базе данных;

для пересылки инструкций SQL в СУБД программа формирует инструкцию в виде текстовой строки и затем передает эту строку в качестве параметра при вызове API-функции;

программа вызывает выполнение API-функции для проверки состояния переданной в СУБД инструкции и обработки ошибок; если инструкция SQL представляет собой запрос на выборку, то, вызывая API-функции, программа записывает результаты запроса в свои переменные; обычно за один вызов возвращается одна строка или столбец данных; свое обращение к базе данных программа заканчивает вызовом

API-функции, отключающей ее от СУБД [8].

186

Соседние файлы в папке лабы