
- •Московский авиационный институт (Государственный технический университет)
- •Управление базами данных
- •4 Семестр
- •Лекция 1
- •Роль sql
- •Преимущества sql
- •Лекция 2
- •Лекция 3
- •Лекция 4
- •Структура предиката в предложении Where
- •Лекция 5
- •Лекция 6
- •Использование множества таблиц в одном запросе.
- •Лекция 7
- •Лекция 8
- •Представления (View)
- •Создание представлений (инструкция create view)
- •Лекция 9
- •Контроль над обновлением представлений (предложение with check option)
- •Лекция 10
- •Лекция 11
- •Триггеры
- •Лекция 12
- •Лекция 13
- •Лекция 14
- •Управление распределенными базами данных
- •Лекция 15
- •Лекция 16
- •Литература
Лекция 10
Возврат значения из процедуры
В дополнение к хранимым процедурам многие диалекты SPL поддерживают хранимые функции. От процедур последние отличаются тем, что возвращают значения, тогда как процедуры этого не делают. Допустим, к примеру, что вы определили хранимую процедуру, которая получает идентификатор клиента и вычисляет общую стоимость его заказов. Если определить эту процедуру как функцию, полученная стоимость может быть возвращена в вызывающую программу.
В большинстве СУБД хранимую функцию можно вызвать в интерактивном режиме, и возвращенное ею значение будет выведено на экран. Если же вызвать функцию из хранимой процедуры, то возвращенное ею значение можно использовать в дальнейших вычислениях или сохранить в переменной.
Многие диалекты SPL допускают использование хранимых функций в выражениях.
Диалект Transact-SQL не поддерживает хранимые функции, хранимые процедуры Transact-SQL могут возвращать код завершения, для чего в них используется инструкция RETURN. Однако возвращаемое значение может быть только целым. Ноль указывает на успешное выполнение процедуры, а отрицательные значения определяют различные виды ошибок. Все системные хранимые процедуры Sybase Adaptive Server и Microsoft SQL Server следуют этому соглашению. Возвращенное хранимой процедурой значение можно сохранить в локальной переменой, используя следующую форму инструкции execute:
declare sts_val int
execute sts__val = add_cust 'XYZ Corporation’, 2317, 30000.00,
50000.00, 103, 'Chicago'
Возврат значений через параметры
Хранимая функция возвращает только одно значение. Однако некоторые диалекты SPL позволяют возвращать из процедуры более одного значения с помощью выходных параметров. Выходные параметры определяются в списке параметров процедуры — так же как и входные, о которых мы говорили ранее. Однако вместо того чтобы передавать данные в процедуру, они служат прямо противоположной цели — возврату данных из хранимой процедуры
Чтобы процедура могла вызвать другую процедуру с выходными параметрами, она должна предоставить для них "буферы", куда будут помещены возвращаемые значения, — ими могут быть локальные переменные или собственные выходные параметры вызывающей процедуры.
В дополнение к входным и выходным параметрам Oracle и Sybase(Watcom-SQL) поддерживает параметры, которые одновременно являются и входными, и выходными (inout) Они передаются хранимой процедуре по тем же правилам, что и обычные выходные параметры, и, кроме того, переданные в них значения используются вызываемой процедурой как входные данные.
Условное выполнение
Одним из базовых элементов хранимых процедур является конструкция IF. . . THEN. . .ELSE, используемая для организации ветвлений внутри процедуры.
Все диалекты SPL допускают создание вложенных инструкций if. В некоторых диалектах даже имеются специальные разновидности условных конструкций, позволяющие организовывать множественное ветвление.
IF search-condition THEN statement-list
... [ ELSEIF search-condition THEN statement-list ] ...
... [ ELSE statement-list ]
... END IF
Циклы
Еще одним базовым элементом хранимых процедур является конструкция для многократного выполнения группы инструкций — проще говоря, цикл. Циклы могут быть разными: в зависимости от используемого диалекта SPL могут поддерживаться циклы FOR со счетчиком итераций (в которых значение целочисленной переменной уменьшается или увеличивается при каждом проходе цикла, пока не достигнет заданного предела) или циклы while, в которых условие продолжения цикла вычисляется в начале или конце группы составляющих его инструкций.
Второй распространенной формой цикла является выполнение последовательности инструкций до тех пор, пока остается или пока не станет истинным заданное условие. Ниже дан примеры такого цикла в Sybase SQL Anywhere. Чтобы этот цикл когда-нибудь остановился, внутри его тела должна осуществляться проверка условия окончания цикла, и если это условие истинно, должна выполняться команда выхода из цикла:
[ statement-label : ]
...[ WHILE search-condition ] LOOP
... statement-list
...END LOOP [ statement-label ]
...
SET i = 1 ;
WHILE i <= 10 LOOP
INSERT INTO Counters( number ) VALUES ( i ) ;
SET i = i + 1 ;
END LOOP ;
...
Или
SET i = 1;
lbl:
LOOP
INSERT
INTO Counters( number )
VALUES ( i ) ;
IF i >= 10 THEN
LEAVE lbl ;
END IF ;
SET i = i + 1 ;
END LOOP lbl
В различных диалектах SPL используются и другие варианты создания циклов, но их возможности и синтаксис аналогичны описанным в этих примерах.
Другие управляющие конструкции
Некоторые диалекты SPL включают дополнительные управляющие конструкции Например, в Informix инструкция exit прерывает нормальное выполнение цикла ц передает управление инструкции, следующей непосредственно за циклом. Инструкция continue также прерывает нормальное выполнение цикла, но вызывает переход к следующей итерации цикла. У обеих инструкций имеется по три формы — для каждого из типов циклов, которые они могут прерывать:
exit for;
continue for;
exit while;
continue while;
exit foreach;
continue foreach;
В Transact-SQL единственная инструкция BREAK заменяет все три варианта инструкции exit; инструкция continue в этом диалекте тоже только одна. В Oracle инструкция exit выполняет ту же функцию, что и в Informix, а инструкция continue отсутствует.
Еще один способ изменения хода выполнения хранимых процедур — это переход по метке, выполняемый инструкцией goto. В большинстве диалектов метка представляет собой идентификатор, за которым следует двоеточие. Как правило, выход по метке за пределы цикла не допускается, как не допускается и переход внутрь цикла или условной конструкции. Следует помнить, что, как и в классических языках программирования, использование инструкции goto не поощряется, поскольку она затрудняет понимание и отладку программ.
Циклическая обработка наборов записей
Одной из самых распространенных ситуаций, в которых требуется циклическое выполнение определенных действий, является построчная обработка набора записей, возвращенного некоторым запросом. Во всех основных диалектах SPL для этого предусмотрены специальные конструкции. Концептуально они подобны встраиваемым в клиентские приложения инструкциям DECLARE CURSOR, OPEN, FETCH И CLOSE встроенного SQL или соответствующим вызовам API-функций Однако результат запроса в данном случае направляется не приложению, а хранимой процедуре, которая выполняется самой СУБД. Соответственно, результирующие данные оказываются не в переменных клиентского приложения, а в локальных переменных хранимой процедуры.
Обработка ошибок
Когда приложение работает с базой данных через интерфейс встроенного SQL или SQL API, оно само отвечает за обработку возникающих при этом ошибок. Коды ошибок возвращаются приложению сервером баз данных, а дополнительную информацию можно получить, вызвав дополнительные API-функции или обратившись к специальной структуре, содержащей диагностическую информацию. Если же операции над данными выполняются хранимой процедурой, она же и должна обрабатывать ошибки
В Transact-SQL информацию о произошедших ошибках можно получить из специальных системных переменных. Имеется огромное количество глобальных системных переменных, хранящих информацию о состоянии сервера и транзакции, открытых подключениях и т.п. Однако для обработки ошибок чаще всего используются только две из них: @@error — код ошибки, произошедшей при выполнении последней инструкции SQL;
@@sqlstatus — состояние последней операции FETCH.
Признаком "нормального завершения" в обеих переменных является значение 0. Другие значения указывают на ошибки или нестандартные ситуации. В хранимых процедурах Transact-SQL глобальные переменные используются точно так же, как локальные. В частности, их можно применять в условиях циклов и в инструкции if.
Преимущества хранимых процедур
Перенос программного кода из клиентских приложений прямо в базу данных в виде хранимых процедур приносит много пользы и администраторам базы данных, и программистам, и конечным пользователям. Вот основные преимущества этого подхода:
Производительность. Многие популярные СУБД компилируют хранимые процедуры (либо автоматически, либо по запросу), создавая их некоторое внутреннее представление. В таком виде процедуры выполняются гораздо быстрее, чем если бы вы динамически компилировали каждую составляющую их инструкцию SQL
Повторное использование кода. После того как хранимая процедура создана, ее можно вызывать из любых приложений, и не нужно снова и снова программировать одни и те же действия, благодаря чему уменьшается риск программных ошибок в клиентских приложениях и экономится время программиста.
Сокращение сетевого трафика. В системах клиент/сервер с точки зрения нагрузки на сеть экономнее пересылать между парой компьютеров только запрос на выполнение хранимой процедуры и получать результаты ее работы, чем обрабатывать каждую инструкцию SQL в отдельности. Особенно это важно в тех случаях, когда сетевой трафик и так слишком высок или пропускная способность соединения очень низкая.
Защита. В большинстве СУБД хранимые процедуры считаются защищаемыми объектами и им назначаются отдельные привилегии. Пользователь, вызывающий хранимую процедуру, должен иметь право на ее выполнение, но не обязательно — права на доступ к таблицам, с которыми она работает (просматривает или модифицирует). Таким образом, администратор базы данных получает более широкие возможности в плане защиты данных и управления доступом пользователей к объектам базы данных.
Инкапсуляция. Идея хранимых процедур хорошо соответствует одной из главных целей объектно-ориентированного программирования (ООП) — инкапсуляции данных и кода в защищенные структуры, доступные только посредством использования ограниченного и строго определенного набора интерфейсов. По терминологии ООП, хранимые процедуры можно назвать методами, посредством которых пользователи или внешние программы могут манипулировать объектами СУБД. Если вы хотите строго придерживаться объектно-ориентированного подхода, нужно с помощью системы защиты СУБД полностью запретить непосредственный доступ к данным через SQL и оставить для доступа к базе данных только хранимые процедуры. Однако столь суровые ограничения мало кем практикуются (если вообще практикуются хоть кем-то).
Производительность хранимых процедур
Различные производители СУБД по-разному реализуют хранимые процедуры. В некоторых системах текст хранимой процедуры находится в базе данных в том виде, в каком он был написан программистом, и интерпретируется только тогда, когда процедура выполняется. Этот подход позволяет создавать для хранимых процедур гибкие языки программирования, но сильно замедляет их выполнение. Ведь СУБД должна прямо по ходу выполнения процедуры читать ее инструкции, осуществлять их синтаксический анализ и определять, что ей следует делать.
Именно по причине низкой производительности интерпретируемых процедур некоторые СУБД предпочитают их заранее компилировать, генерируя некий промежуточный код, который выполняется гораздо быстрее. Компиляция может происходить автоматически сразу после создания процедуры или по запросу пользователя. Однако у предварительной компиляции хранимых процедур есть свой недостаток: точный процесс выполнения процедуры фиксируется во время ее компиляции и уже не может быть изменен. Чем же это плохо? Предположим, что после компиляции процедуры были определены дополнительные индексы для таблиц, с которыми она работает. Скомпилированные запросы этой процедуры были оптимизированы без учета новых индексов и будут выполняться медленнее, чем могли бы в случае, если их перекомпилировать.
Для решения этой проблемы некоторые СУБД автоматически помечают все скомпилированные процедуры, на которых могли отразиться изменения объектов базы данных, как нуждающиеся в повторной компиляции. Когда такая процедура в очередной раз вызывается, СУБД видит пометку и компилирует процедуру перед ее выполнением. Так сохраняется преимущество предварительной компиляции, и процедуры выполняются оптимальным образом. Но и у этого подхода остается один недостаток: непредсказуемые задержки в выполнении процедур, связанные с их динамической перекомпиляцией. Когда повторная компиляция не нужна, хранимая процедура может выполниться очень быстро; если же процедуру потребовалось перекомпилировать, перед ее выполнением может быть довольно ощутимая задержка.
Чтобы выяснить, как компилируются хранимые процедуры конкретной СУБД, можно посмотреть, какие опции имеются для инструкций create procedure, execute PROCEDURE, ALTER PROCEDURE и др.
Системные хранимые процедуры
Если СУБД поддерживает хранимые процедуры, то, скорее всего, в ней есть и некоторый набор готовых системных процедур, которые автоматизируют различные операции с базой данных и некоторые функции ее администрирования. Пионером создания системных хранимых процедур была Sybase, включившая их в свой продукт Sybase SQL Server. Сегодня их уже сотни, и они облегчают выполнение множества полезных функций, таких как, например, управление учетными записями пользователей, заданиями, распределенными серверами, репликацией и т.д. Большинство системных процедур Transact-SQL названо в соответствии со следующими соглашениями:
SP_ADD<имя> — добавление нового объекта (пользователя, сервера, реплики и т.п.);
SP_DROP — удаление существующего объекта;
SP_HELP<имя> — получение информации об объекте или объектах. Например, процедура sp_helpuser возвращает информацию о пользователях текущей базы данных.
Хотя на расширенных диалектах SQL большинства ведущих СУБД можно писать довольно мощные хранимые процедуры, их возможности все же ограниченны. Одним из их главных ограничений является отсутствие "связи с внешним миром", т.е. Доступа к функциям операционной системы и приложений, работающих в той же системе. Кроме того, расширенные диалекты SQL — это языки очень высокого уровня, не предназначенные для низкоуровневого программирования, обычно выполняющегося на С или C++. Для преодоления этих ограничений в большинстве СУБД можно обращаться к внешним хранимым процедурам.
Внешняя хранимая процедура — это процедура, написанная на одном из традиционных языков программирования (например, на С или Pascal) и скомпилированная вне СУБД. Для ее использования нужно предоставить СУБД объявление процедуры — ее имя, параметры и другую информацию, необходимую для ее вызова. После этого можно вызывать внешнюю процедуру точно так же, как и обычные хранимые процедуры базы данных, написанные на SQL. СУБД обрабатывает вызов и передает управление внешней процедуре, а по окончании ее работы снова получает управление и принимает возвращенные процедурой данные.
Microsoft SQL Server предоставляет программистам набор системных внешних процедур, обеспечивающих доступ к функциям операционной системы. Например процедура xp__sendmail позволяет отправлять пользователям электронные почтовые сообщения с информацией о событиях, происходящих в базе данных:
XP_SENDMAIL @RECIPIENTS = 'Joe’, 'Sam', SMESSAGE = 'Отчет готов';
Другая процедура, xp_cmdshell, выполняет команды операционной системы, в которой работает SQL Server. Допускается также создание пользовательских внешних процедур, которые хранятся в библиотеках динамической компоновки (DLL) и вызываются из хранимых процедур SQL Server.
Informix обеспечивает доступ к функциям операционной системы с помощью специальной инструкции SYSTEM. Кроме того, эта СУБД поддерживает пользовательские внешние процедуры, для объявления которых предназначена инструкция CREATE procedure. Там, где обычно начинается тело хранимой процедуры Informix, помещается предложение external, в котором задается имя, местоположение и язык внешней процедуры. Объявленную таким образом процедуру можно вызывать как обычную хранимую процедуру Informix.
Ту же возможность предоставляют и новые версии Oracle (Oracle8 и выше) — в них внешние процедуры тоже объявляются с помощью инструкции create procedure. Семейство продуктов DB2 компании IBM обеспечивает аналогичный набор возможностей.
Контрольные вопросы
Какие виды параметров существуют у хранимых процедур?
Что такое хранимые функции?
Какие операторы SPL(stored procedure language) организации циклов?
Перечислите преимущества хранимых процедур.
Как хранимые процедуры влияют на производительность?