Операторы Pl / SQL Bulk Bind / Faster Update - PullRequest
0 голосов
/ 08 марта 2012

У меня проблемы с использованием Bulk Bind в PL / SQL.В основном я хочу, чтобы таблица (Component) обновляла свое значение поля в зависимости от Component_id и fieldname.Все они передаются как параметры (тип varchar2_nested_table - это эффективно и массив строк, один элемент для каждого оператора обновления, который должен произойти).Так, например, если Component_id = 'Compid1' и fieldname = 'name', тогда fieldvalue должно быть обновлено, чтобы быть 'новым именем компонента'.

Я набрал код ниже относительно этого http://www.oracle.com/technetwork/issue-archive/o14tech-plsql-l2-091157.html.Код работает, но не быстрее простого цикла, который выполняет обновление для каждого элемента в параметрах IN.Таким образом, если параметры имеют 1000 элементов, то будет выполнено 1000 операторов обновления.Я также понимаю, что не использую BULK COLLECT INTO, но я не думал, что мне это нужно, так как мне не нужно ничего выбирать из базы данных, просто обновите.

В данный момент обе операции занимают 4-5секунд на 1000 обновлений.Я предполагаю, что я использую массовое связывание неправильно или у меня неправильное понимание предмета, поскольку в примерах я могу обнаружить, что люди выполняют 50 000 строк за 2 секунды и т. Д. Насколько я понимаю, FORALL должен повысить производительность за счет уменьшения количества переключений контекста.Я попробовал другой метод, который я нашел онлайн, используя курсоры и массовые привязки, но у меня был тот же результат.Возможно, мои ожидания по производительности слишком велики?Я так не думаю, увидев результаты других.Любая помощь будет принята с благодарностью.

create or replace procedure BulkUpdate(sendSubject_in IN varchar2_nested_table_type,
fieldname_in IN varchar2_nested_table_type,fieldvalue_in IN   varchar2_nested_table_type) is


TYPE component_aat IS TABLE OF component.component_id%TYPE
  INDEX BY PLS_INTEGER;
TYPE fieldname_aat IS TABLE OF component.fieldname%TYPE
  INDEX BY PLS_INTEGER;
TYPE fieldvalue_aat IS TABLE OF component.fieldvalue%TYPE
  INDEX BY PLS_INTEGER;

fieldnames fieldname_aat;
fieldvalues fieldvalue_aat;
approved_components component_aat;


PROCEDURE partition_eligibility
IS
BEGIN
  FOR indx IN sendSubject_in.FIRST .. sendSubject_in.LAST
  LOOP
    approved_components(indx) := sendSubject_in(indx);
    fieldnames(indx):= fieldname_in(indx);
    fieldvalues(indx) := fieldvalue_in(indx);
  END LOOP;
END;


PROCEDURE update_components
IS
BEGIN
  FORALL indx IN approved_components.FIRST .. approved_components.LAST
    UPDATE Component
      SET Fieldvalue = fieldvalues(indx)
      WHERE Component_id = approved_components(indx)
      AND Fieldname = fieldnames(indx);
END;

BEGIN
  partition_eligibility;
  update_components;
END BulkUpdate;

Ответы [ 2 ]

0 голосов
/ 20 февраля 2017

Всякий раз, когда мы отправляем блоки PL / SQL на сервер Oracle, всегда выполняются операторы SQL.Через движок SQL а также выполняются процедурные утверждения.Через процессуальное заявление исполнителя.Этот исполнитель процедурных операторов доступен в движке PL / SQL, когда мы используем большую нагрузку через SQL, операторы PL / SQL всегда сервер oracle выполняет эти операторы отдельно через эти механизмы.методология выполнения переключения контента снижает производительность приложения.Чтобы преодолеть эту проблему, oracle ввел процесс «массового связывания» с использованием коллекций, т.е. в этом методе сервер oracle выполняет все операторы SQL одновременно.Bulk Collect:

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

  1. select… into… предложение
  2. оператор извлечения курсора
  3. возвращающие предложения DML

Также см. PL / SQL Массовый сбор и массовое связывание

0 голосов
/ 08 марта 2012

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

Вот мои настройки теста:

CREATE TABLE Component (
  Component_id NUMBER,
  fieldname    VARCHAR2(100),
  Fieldvalue   VARCHAR2(100),
  CONSTRAINT component_pk PRIMARY KEY (component_id, fieldname)
);

-- insert 1 million rows
INSERT INTO component 
  (SELECT ROWNUM, to_char(MOD(ROWNUM, 100)), dbms_random.string('p', 10) 
     FROM dual 
   CONNECT BY LEVEL <= 1e6);

CREATE OR REPLACE TYPE varchar2_nested_table_type AS TABLE OF VARCHAR2(100);
/

SET SERVEROUTPUT ON SIZE UNLIMITED FORMAT WRAPPED
DECLARE
   l_id    varchar2_nested_table_type;
   l_names varchar2_nested_table_type;
   l_value varchar2_nested_table_type;
   l_time  NUMBER;
BEGIN
   SELECT rownum, to_char(MOD(rownum, 100)), dbms_random.STRING('p', 10) 
     BULK COLLECT INTO l_id, l_names, l_value
     FROM dual
   CONNECT BY LEVEL <= 100000;
   l_time := dbms_utility.get_time;
   BulkUpdate(l_id, l_names, l_value);
   dbms_output.put_line((dbms_utility.get_time - l_time) || ' cs elapsed.');
END;
/

100000 строк обновляются примерно за 1,5 секунды на ничем не примечательной тестовой машине.Обновление одного и того же набора данных построчно занимает около 4 секунд.

Можете ли вы запустить аналогичный сценарий с только что созданной таблицей?

...