Выбрать главу

Выполняемые процедуры

В DSQL оператор EXECUTE PROCEDURE выполняет (вызывает) выполняемую хранимую процедуру - хранимую процедуру, созданную для выполнения некоторых операций на сервере, - возвращая (необязательно) одну строку из одного или более значений. Оператор для выполнения подобных процедур имеет следующий общий формат:

EXECUTE PROCEDURE ИМЯ-процедуры

[(<список входных значений>)

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

EXECUTE PROCEDURE DO_IT(49, '25-DEC-2004');

В приложениях более мощным средством является использование параметров (см. разд. "Использование параметров") в операторах запросов, которые выполняют хранимые процедуры, например:

EXECUTE PROCEDURE DO_IT(:IKEY, :KEPORT_DATE) ;

или

EXECUTE PROCEDURE DO_IT(?, ?);

Процедуры выбора

Хранимые процедуры выбора способны возвращать многострочные наборы данных в ответ на специализированную форму оператора SELECT:

SELECT <список выходных столбцов>

FROM имя-процедуры [ (<список входных значений>) ]

[WHERE <предикаты поиска>]

[ORDER BY <список выходных столбцов>]

В следующем фрагменте PSQL хранимая процедура принимает один ключ в качестве входного параметра и возвращает множество строк. Предложение RETURNS определяет выходной набор:

CREATE PROCEDURE GET_COFFEE_TABLE (IKEY INTEGER)

RETURNS (

BRAND_ID INTEGER,

VARIETY_NAME VARCHAR(40),

COUNTRY_OF_ORIGIN VARCHAR(30))

AS . . . . . .

Приложение получает выходной набор из хранимой процедуры следующим образом:

SELECT BRAND_ID, VARIETY_NAME, COUNTRY_OF_ORIGIN FROM GET_COFFEE_TABLE (5002) ;

Тот же самый пример с параметризованным входным аргументом:

SELECT BRAND_ID, VARIETY_NAME, COUNTRY_OF_ORIGIN FROM GET_COFFEE_TABLE(:IKEY);/* Delphi */

или

SELECT BRAND_ID, , VARIETY_NAME, COUNTRY_OF_ORIGIN FROM GET_COFFEE_TABLE(?);

Использование параметров

"Непараметризованный" запрос использует константы в выражениях для условий поиска. Например, в запросе

SELECT MAX(COST * QUANTITY)

AS BEST_SALE FROM SALES

WHERE SALESEDATE > '31.12.2003' ;

будут обработаны те строки таблицы SALES, у которых дата в SALES_DATE более поздняя, чем последний день 2003 года.

Средства разработки доступа к данным, использующие API Firebird, имеют возможность обрабатывать константы в условиях поиска как заменяемые параметры. API позволяет передавать на сервер оператор в виде шаблона, представляющего эти параметры как заполнители, которые могут заменяться конкретными значениями. Клиент запрашивает подготовку (prepare) оператора - проверка синтаксиса и метаданных - без фактического его выполнения.

Приложение DSQL может создать оператор с динамическими условиями поиска в предложении WHERE, один раз подготовить его, а затем присваивать параметрам значения один или много раз непосредственно перед каждым выполнением. Такую возможность иногда называют динамическим связыванием. Средства разработки приложений отличаются по тем способам, которыми они реализуют динамическое связывание параметров во включающем языке. В зависимости от того, какое средство разработки вы используете, параметризованная версия последнего примера может выглядеть несколько иначе, например, так:

SELECT MAX (COST * QUANTITY) AS BEST_SALE

FROM SALES

WHERE SALES_DATE > ? ;

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

API "знает" порядок и формат параметров, потому что приложение передает описательные структуры XSQLDA, которые содержат массив SQLVAR- дескрипторы переменных, описывающих каждый параметр, - и другие данные, описывающие массив в целом.

Delphi и другие объектно-ориентированные реализации API используют методы и свойства классов, чтобы скрыть от разработчика механизм, применяемый для создания и управления сырым оператором и дескрипторами. Другие средства разработки кодируют эти структуры иным образом. Оператор может передаваться на сервер приблизительно в таком виде:

INSERT INTO DATATABLE (DATAl, DATA2, DATA3, DATA4, DATA5,... другие столбцы)

VALUES (?, '?', '?', ?, ?, ... другие значения);

Если параметры реализованы в языке программирования вашего приложения, то весьма рекомендуется их использовать.

Замечания для пользователей Delphi

Delphi, имеющее клеймо "made in Borland", как и InterBase, предшественник Firebird, при передаче переменных включающего языка реализует формат, который повторяет формат, используемый в PSQL для ссылки на локальные переменные в SQL- операторах и ESQL. Он требует, чтобы все параметры были явно именованы и начинались с символа двоеточия. В Delphi предыдущий простой пример может быть представлен в свойстве SQL объекта доступа к данным в следующем виде:

SELECT MAX(COST * QUANTITY) AS BEST_SALE

FROM SALES

WHERE SALES_DATE > :SALES_DATE ;

Один вызов метода PREPARE приведет к проверке оператора и передаче описания метаданных назад в клиентское приложение; объект доступа к данным позволяет позже присваивать значение параметру, используя локальный метод, который выполняет преобразование значения к формату, требуемому в Firebird:

aQuery.ParamByName ('SALES_DATE').AsDate := ALocalDateVariable;

Пакетные операции

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

Пакетные добавления

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

INSERT INTO DATATABLE(DATA1, DATA2, DATA3, DATA4, DATA5, . . . другие столбцы)

VALUES ('x', 'у', 'z', 99, '2004-12-25', . . . другие значения);

При использовании параметров он будет выглядеть так:

INSERT INTO DATATABLE(DATA1, DATA2, DATA3, DATA4, DATA5, . . . другие столбцы)

VALUES (?, '?', '?', ?, ?, .... другие значения);

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

Предотвращение замедления пакетной операции

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

* Использование индексов, которые добавляют задаче работы, а также имеют тенденцию к деформированию геометрии индексных деревьев.

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