как запустить хранимую процедуру в пакетном режиме или запустить ее в параллельной обработке

Мы повторяем более 100 тыс. записей из глобальной временной таблицы. Ниже хранимая процедура будет перебирать все записи из глобальной временной таблицы одну за другой и должна обрабатывать менее трех шагов.

  1. чтобы увидеть, существует ли продукт или нет
  2. чтобы увидеть, имеет ли продукт внутри активов «категорию» или нет.
  3. чтобы увидеть, имеют ли ресурсы имена файлов, начинающиеся с «% pdf%» или нет.

Таким образом, каждая запись должна выполнить эти 3 шага, и окончательные имена документов будут сохранены в таблице для успешной записи. Если на каком-либо из шагов возникает какая-либо ошибка, для этой записи будет сохранено сообщение об ошибке.

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

  1. Есть ли способ ускорить этот процесс в самой хранимой процедуре, выполнив пакетный процесс?
  2. Если это невозможно в хранимой процедуре, можем ли мы изменить этот код на Java и запустить этот код в многопоточном режиме? например, создать 10 потоков, и каждый поток будет одновременно принимать одну запись и обрабатывать этот код. Буду рад, если кто-нибудь даст какой-нибудь псевдокод.

какой подход собирается предложить?

DECLARE
V_NODE_ID  VARCHAR2(20);
V_FILENAME VARCHAR2(100);
V_CATEGORY_COUNT INTEGER :=0;  
FINAL_FILNAME VARCHAR2(2000);
V_FINAL_ERRORMESSAGE VARCHAR2(2000);


CURSOR C1 IS
SELECT isbn FROM GT_ADD_ISBNS GT;

CURSOR C2(v_isbn in varchar2) IS
SELECT ANP.NODE_ID NODE_ID
        FROM 
        table1 ANP,
        table2 ANPP,
        table3 AN
        WHERE 
      ANP.NODE_ID=AN.ID AND
    ANPP.NODE_ID=ANP.NODE_ID AND
    AN.NAME_ID =26 AND
    ANP.CATEORGY='category' AND
    ANP.QNAME_ID='categories'  AND
        ANP.NODE_ID IN(SELECT CHILD_NODE_ID 
                  FROM TABLE_ASSOC START WITH PARENT_NODE_ID IN(v_isbn) 
                      CONNECT BY PRIOR CHILD_NODE_ID = PARENT_NODE_ID);


BEGIN
--Iterating all Products
FOR R1 IN C1 
LOOP

FINAL_FILNAME :='';
BEGIN


--To check whether Product is exists or not
SELECT AN.ID INTO V_NODE_ID 
FROM TABLE1 AN,
TABLE2 ANP
WHERE
AN.ID=ANP.NODE_ID AND
ANP.VALUE in(R1.ISBN);


V_CATEGORY_COUNT :=0;
V_FINAL_ERRORMESSAGE :='';

--To check Whether Product inside the assets are having the 'category' is applied or not
FOR R2 IN C2(R1.ISBN) 
LOOP

V_CATEGORY_COUNT := V_CATEGORY_COUNT+1;  

BEGIN
--In this Logic Product inside the assets have applied the 'category' But those assets are having documents LIKE '%pdf%' or not
SELECT ANP.STRING_VALUE  into V_FILENAME
        FROM 
        table1 ANP,
        table2 ANPP,
        table3 ACD
        WHERE 
       ANP.QNAME_ID=21  AND 
       ACD.ID=ANPP.LONG_VALUE 
       ANP.NODE_ID=ANPP.NODE_ID AND
       ANPP.QNAME_ID=36 AND
       ANP.STRING_VALUE LIKE '%pdf%'  AND 
       ANP.NODE_ID=R2.NODE_ID; 

    FINAL_FILNAME := FINAL_FILNAME  || V_FILENAME ||',';

   EXCEPTION WHEN
     NO_DATA_FOUND THEN
     V_FINAL_ERRORMESSAGE:=V_FINAL_ERRORMESSAGE|| 'Category is applied for this Product But for the asset:'||  R2.NODE_ID || ':Documents[LIKE %pdf%] were not found ;';
     UPDATE GT_ADD_ISBNS SET ERROR_MESSAGE=  V_FINAL_ERRORMESSAGE  WHERE ISBN= R1.ISBN;


     END;--Iterating for each NODEID

END LOOP;--Iterating the assets[Nodes] for each product of catgeory

  --  DBMS_OUTPUT.PUT_LINE('R1.ISBN:' || R1.ISBN ||'::V_CATEGORY_COUNT:' || V_CATEGORY_COUNT);

 IF(V_CATEGORY_COUNT  = 0) THEN
     UPDATE GT_ADD_ISBNS SET ERROR_MESSAGE=  'Category is not applied to none of the Assets for this Product'  WHERE ISBN= R1.ISBN;
   END IF;  


EXCEPTION WHEN
NO_DATA_FOUND THEN
      UPDATE GT_ADD_ISBNS SET ERROR_MESSAGE=   'Product is not Found:' WHERE ISBN= R1.ISBN;
END;

  -- DBMS_OUTPUT.PUT_LINE( R1.ISBN || 'Final documents:'||FINAL_FILNAME);
      UPDATE GT_ADD_ISBNS SET FILENAME=FINAL_FILNAME WHERE ISBN= R1.ISBN;

COMMIT;
END LOOP;--looping gt_isbns
END;

person user739115    schedule 20.02.2018    source источник
comment
Добавьте дополнительный столбец части во временную таблицу и назначьте номера 1-10 всем записям в циклическом режиме. Измените хранимую процедуру, чтобы обрабатывать только 1 часть. Теперь запустите хранимую процедуру 10 раз параллельно для каждой части.   -  person Andreas    schedule 20.02.2018
comment
А еще лучше настройте свой SQL. Обработка более 100 000 записей не должна занимать много времени, хотя вы и не определяете, что означает «долго».   -  person Andreas    schedule 20.02.2018
comment
для завершения этого процесса требуется 15-16 часов. Обратите внимание, что логика запроса верна, используются необходимые соединения и необходимые индексы есть в столбцах. После добавления столбца части и добавления чисел. Нужно ли мне что-либо менять в хранимой процедуре?   -  person user739115    schedule 20.02.2018


Ответы (1)


У вас есть ряд потенциальных хитов производительности. Вот один:

«Мы повторяем более 100 000 записей из глобальной временной таблицы»

Глобальные временные таблицы могут быть довольно медленными. Их заполнение означает запись всех этих данных на диск; чтение с них означает чтение с диска. Это много операций ввода-вывода, которых можно было бы избежать. Кроме того, GTT используют временное табличное пространство, поэтому вы можете конфликтовать с другими сеансами, выполняющими большие сортировки.

Вот еще один красный флаг:

FOR R1 IN C1 LOOP
... FOR R2 IN C2(R1.ISBN) LOOP

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

--To check whether Product is exists or not

У вас несколько запросов на выборку из одних и тех же таблиц (AN, 'ANP) using the same criteria (isbn`). Возможно, все эти дубликаты — единственный способ проверить ваши бизнес-правила, но это маловероятно.

FINAL_FILNAME := FINAL_FILNAME || V_FILENAME ||',';

Может быть, вы могли бы переписать свой запрос, чтобы использовать listagg() вместо использования процедурной логики для объединения строк?

UPDATE GT_ADD_ISBNS

Опять же, все ваши обновления — это операции с одной строкой, а не с набором.

«Есть ли способ ускорить этот процесс в самой хранимой процедуре, выполнив пакетный процесс?»

Не зная ваших правил и контекста, мы не можем переписать вашу логику за вас, но 15-16 часов слишком много для этого, так что вы определенно можете сократить затраченное время.

Что следует учитывать:

  1. Замените запись и чтение во временную таблицу запросом, который вы используете для ее заполнения.
  2. Перепишите циклы, чтобы использовать BULK COLLECT с высоким LIMIT (например, 1000), чтобы повысить эффективность выбора. Подробнее.
  3. Заполните массивы и используйте FORALL для повышения эффективности обновлений. Подробнее.
  4. Попробуйте удалить все эти отдельные поиски, включив логику в основной запрос, используя синтаксис OUTER JOIN для проверки существования.

Это все догадки. Если вы действительно хотите знать, на что процедура тратит время - а это знание является корнем любой успешной настройки, поэтому вам следует хотеть знать - вы должны запускать процедуру под PL/SQL Profiler. Это скажет вам, какие линии стоят больше всего времени, и обычно именно на них вам нужно сосредоточить свои усилия по настройке. Если у вас еще нет доступа к DBMS_PROFILER, вам потребуется администратор базы данных, чтобы запустить сценарий установки. Подробнее.

"Можем ли мы преобразовать этот код в Java и запустить этот код в многопоточном режиме?"

Учитывая, что одной из причин замедления процедуры является стоимость операций ввода-вывода при выборе из временной таблицы, велика вероятность того, что многопоточность может привести к дальнейшему конфликту и даже усугубить ситуацию. Сначала следует попытаться улучшить хранимую процедуру.

person APC    schedule 20.02.2018