Пакетное добавление
Возможны два режима добавления строк в таблицу: обычный и пакетный.
В обычном режиме добавление строки выполняется с помощью SQL-оператора INSERT. Строки добавляются по одной при каждом исполнении данного оператора.
В пакетном режиме строки добавляются за одну операцию в том количестве, в каком они заданы во входном буфере. Пакетный режим рекомендуется использовать при загрузке больших объемов данных.
Для выполнения пакетного добавления внутри хранимой процедуры:
-
определить курсор, в котором имена полей соответствуют именам (и типам) полей загружаемой таблицы. Если имя поля таблицы содержит нестандартные символы, совпадает с ключевым словом и т.д. (т.е. требует квотации), в описании поля курсора можно явно указать имя, какое должно использоваться. Для этого после типа столбца можно указать ключевое слово column и строку в кавычках, например:
cursor( i int; // будет соответствовать столбцу "I" l char(20) column "lowercase" // будет соответствовать столбцу "lowercase" ins date column "INSERT" // будет соответствовать столбцу "INSERT" );
-
перед добавлением выдать оператор:
start append into <таблица> from <курсор>;
где:
<таблица>– имя таблицы;<курсор>– курсорная переменная.Выполнение этого оператора внутри процедуры приводит к подаче SQL-запроса
start append into byte(<список столбцов>согласно именам полей в таблице).В случае ошибки при выполнении оператора формируется исключение с кодом завершения.
В случае если
<курсор>– недопустимое выражение, вызывается исключениеBADPARAM.При попытке выполнить
start appendилиexecute, когда предыдущийstart appendне был завершен при помощиend append, возникает исключениеAPPENDACTIVE. -
чтобы добавить строку, надо заполнить поля соответствующими значениями и выдать оператор:
putm <буфер>;
В качестве
<буфера>можно использовать любую переменную типа курсор, структура которой совпадает со структурой переменной, использованной в операторе start append. В случае несовпадения возникнет исключениеBADCURSOR.Этот оператор накапливает данные во внутренней странице пакета (которая выделяется оператором
start append) и, если пакет заполняется, загружает его в таблицу.Если в процессе формирования пакета и загрузки его в таблицу возникает ошибка, то вырабатывается исключение с кодом завершения, который можно получить с помощью функции errcode().
Если возникает ошибка, внутренняя страница продолжает содержать данные, которые не удалось добавить, а новая запись игнорируется.
Чтобы очистить внутреннюю страницу, можно использовать функцию
clearPutm()Узнать количество записей во внутренней странице (которые еще не занесены реально в БД) можно при помощи функции
int getPutmRecs()Эту функцию можно использовать, в частности, после возникновения ошибки в
putm. Ошибка означает, что не все записи из внутренней страницы добавлены. ФункцияgetPutmRecs()позволяет узнать, сколько именно записей не добавлено, чтобы попытаться добавить эти последние n записей по одной, проверяя, какая именно из записей пакета ошибочна.
Можно потребовать принудительно сбросить записи из внутренней страницы в БД при помощи функции
flushPutm()В случае успеха внутренняя страница освобождается для последующей нормальной работы.
В случае ошибки обработка внутренней страницы аналогична выполнению оператора
putm, попытавшегося сбросить заполненную внутреннюю страницу и столкнувшегося с ошибкой: внутренняя страница не очищается. Очистить ее всегда можно при помощиclearPutm().Таким образом, вызов подряд
putmиflushPutm()приведет, фактически, к добавлению строк по одной через механизм пакетного добавления.Если перед подачей
putmвызовом функцийgetPutmRecs,clearPutmиflushPutmне был выполнен операторstart append, или он завершился неудачно, то при попытке выполнитьputmвозникнет исключениеAPPENDNOTSTARTED. -
по окончании добавления надо выдать оператор
end append.Если перед подачей
end appendне было вызвано оператораstart append, или он завершился неудачно, то при попытке выполнитьend appendвозникнет исключениеAPPENDNOTSTARTED.После каждого
start appendдолжен вызыватьсяend append, прежде чем делать другиеexecuteилиstart append! -
все операции
putmвыполняются по одному курсору, по тому же, что иexecuteв процедурах ("курсору по умолчанию").Соответственно, между
start appendиend appendнельзя использовать другиеstart appendилиexecute. Если пытаться сделать это, возникнет исключениеQUERYWHENAPPEND(если его не обработать, последующая попытка выполнения SQL-оператора приведет к получению кода завершения 1013 – неверная последовательность команд).
Примечание
При пакетной вставке данных триггеры, настроенные на вставку данных, срабатывать не будут.
Пример
create or replace procedure "PM"() result char(20) for debug
declare
var c cursor(i int column "start",
si smallint, bi bigint,
c char(20), vc varchar(30),
d date column "THIS IS DATE",
r real, db double, dc numeric,
l bool,
b byte(10), vb varbyte(10)
);
var i int;
exception APPENDNOTSTARTED for APPENDNOTSTARTED;
exception QUERYWHENAPPEND for QUERYWHENAPPEND;
exception APPENDACTIVE for APPENDACTIVE;
exception AAA for 116;
code
execute direct "drop table pm;";
execute "create table pm("
"\"start\" int, si smallint, bi bigint,"
"c char(20), vc varchar(30), "
"\"THIS IS DATE\" date,"
"r real, db double, dc numeric,"
"l boolean,"
"b byte(10), vb varbyte(10));";
start append into "PM" from c;
i := 1;
while i < 32001 loop
c.i := i;
c.si := i;
c.bi := i*100;
c.c := "string value "+tochar(i);
c.vc := c.c + " ";
c.d := sysdate() + i;
c.r := i/10.0;
c.db := i/100.0;
c.dc := i/1000.0;
c.l := mod(i, 10) = 0;
asc(tochar(i), c.vb);
asc(tochar(sysdate()+i), c.b);
putm c;
if errcode() <> 0 then
return "PUTM error: "+tochar(errcode());
endif
i := i+1;
endloop
end append;
if errcode() <> 0 then
return "Error "+tochar(errcode());
endif
return "Ok";
exceptions
when AAA then
return "PUTM failed";
when APPENDNOTSTARTED then
return "APPENDNOTSTARTED";
when APPENDACTIVE then
return "APPENDACTIVE";
when QUERYWHENAPPEND then
return "QUERYWHENAPPEND";
end;
При сравнении этой процедуры с процедурой, которая добавляет те же строки не в пакетном режиме, а по одной (с помощью insert), были получены следующие характеристики.
Время работы: 10 000 строк: insert: 33 с. putm: 11 с. 32 000 строк: insert: 2 мин. putm: 36 с.
Если добавлять меньше столбцов, выигрыш от putm более очевидный.
Для 4 столбцов и 10 000 строк: insert: 26 с. putm: 5 с.