Пакетное добавление
Возможны два режима добавления строк в таблицу: обычный и пакетный.
В обычном режиме добавление строки выполняется с помощью 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 с.