Я работаю над проектом хранилища данных, и поэтому я реализую некоторые ETL функции в пакетах.Сначала я столкнулся с проблемой на моем развивающемся ноутбуке и подумал, что это как-то связано с моей установкой Oracle, но теперь он «распространился» на рабочие серверы.Две функции «иногда» становятся невероятно медленными.Мы внедрили систему ведения журналов, предоставляя нам вывод в таблицу журналирования каждые х строк.Когда функции обычно требуется около 10 секунд на фрагмент, «иногда» функциям требуется до 3 минут.После перестройки некоторых индексов и перезапуска функции она снова выполняется так же быстро, как и раньше.К сожалению, я не могу сказать, какой именно это индекс, поскольку перезапуск функции и создание курсора, который она использует для своей работы, занимает некоторое время, и у нас нет времени, чтобы проверить каждый индекс самостоятельно, поэтому я просто перестроил всеиндексы, которые потенциально используются функцией, и перезапустите ее.
Функции, в которых возникла проблема, используют курсор для выбора данных из таблицы с приблизительно 50–200 миллионами записей, соединенных небольшой таблицей с приблизительно 50-500 записей.Условие соединения - это сравнение строк.Затем мы используем первичный ключ из маленькой таблицы, которую мы получаем из объединения, чтобы обновить внешний ключ в главной таблице.Процесс обновления выполняется с помощью повторяющегося цикла, что, как оказалось, позволяет сэкономить много времени.
Вот упрощенная версия структуры таблиц обеих таблиц:
CREATE TABLE "maintable"
( "pkmid" NUMBER(11,0) NOT NULL ENABLE,
"fkid" NUMBER(11,0),
"fkstring" NVARCHAR2(4) NOT NULL ENABLE,
CONSTRAINT "PK_MAINTABLE" PRIMARY KEY ("pkmid");
CREATE TABLE "smalltable"
( "pksid" NUMBER(11,0) NOT NULL ENABLE,
"pkstring" NVARCHAR2(4) NOT NULL ENABLE,
CONSTRAINT "PK_SMALLTABLE" PRIMARY KEY ("pksid");
Обе таблицы имеютиндексы на их строковых столбцах.Добавляя первичные ключи, я каждый раз перестраиваю 4 индекса каждый раз, когда возникает проблема.
Мы получаем наши данные таким образом, что у нас есть только fkstring в основной таблице, а fkid имеет значение null.На первом этапе мы заполняем небольшой стол.Это занимает всего несколько минут и выполняется следующим образом:
INSERT INTO smalltable (pksid, pkstring)
SELECT SEQ_SMALLTABLE.NEXTVAL, fkstring
FROM
(
SELECT DISTINCT mt.fkstring
FROM maintable mt
MINUS
SELECT st.pkstring
FROM smalltable st
);
commit;
Эта функция никогда не вызывает проблем.
Следующая функция работает (это упрощенная версия функции - я удалилаведение журнала и обработка исключений и переименование некоторых переменных):
function f_set_fkid return varchar2 is
cursor lCursor_MAINTABLE is
SELECT MT.PKmID, st.pksid
FROM maintable mt
JOIN smalltable st ON (mt.fkstring = st.pkstring)
WHERE mt.fkid IS NULL;
lIndex number := 0;
lExitLoop boolean := false;
type lCursorType is table of lCursor_MAINTABLE%rowtype index by pls_integer;
lCurrentRow lCursor_MAINTABLE%rowtype;
lTempDataArray lCursorType;
lCommitEvery constant number := 1000;
begin
open lCursor_MAINTABLE;
loop
-- get next row, set exit condition
fetch lCursor_MAINTABLE into lCurrentRow;
if (lCursor_MAINTABLE%notfound) then
lExitLoop := true;
end if;
-- in case of cache being full, flush cache
if ((lTempDataArray.count > 0) AND (lIndex >= lCommitEvery OR lExitLoop)) then
forall lIndex2 in lTempDataArray.FIRST..lTempDataArray.LAST
UPDATE maintable mt
set fkid = lTempDataArray(lIndex2).pksid
WHERE mt.pkmid = lTempDataArray(lIndex2).pkmid;
commit;
lTempDataArray.delete;
lIndex := 0;
end if;
-- data handling, fill cache
if (lExitLoop = false) then
lIndex := lIndex + 1;
lTempDataArray(lIndex). := lCurrentRow;
end if;
exit when lExitLoop;
end loop;
close lCursor_MAINTABLE;
return null;
end;
Я был бы очень благодарен за любую помощь.
PS Я знаю, что массовый сбор в ускорит функцию и, вероятно, такженемного упростить код, но в данный момент мы довольны скоростью функции, которая обычно есть.Изменение функции для использования группового сбора входит в наш план на следующий год, но на данный момент это не вариант (и я сомневаюсь, что это решит эту проблему индекса).