0

PL/SQL でバルク バインドを使用すると問題が発生します。基本的に私が欲しいのは、テーブル(コンポーネント)がComponent_idとフィールド名に応じてフィールド値を更新することです。これらはすべてパラメーターとして渡されます (タイプ varchar2_nested_table は事実上文字列の配列であり、発生する必要がある更新ステートメントごとに 1 つの要素です)。たとえば、Component_id = 'Compid1' および fieldname = 'name' の場合、fieldvalue は '新しいコンポーネント名' になるように更新する必要があります。

このhttp://www.oracle.com/technetwork/issue-archive/o14tech-plsql-l2-091157.htmlに関連して、以下のコードを入力しました。コードは機能しますが、IN パラメーターのすべての要素に対して更新を実行する単純なループよりも高速ではありません。したがって、パラメーターに 1000 個の要素がある場合、1000 個の更新ステートメントが実行されます。また、BULK COLLECT INTO を使用していないことも認識していますが、データベースから何も選択する必要がなく、更新するだけなので、必要だとは思いませんでした。

現時点では、どちらも 1000 回の更新に 4 ~ 5 秒かかります。バルクバインドを間違って使用しているか、例のように主題を誤解していると思います.2秒で50,000行を実行している人がいるなどです。私が理解していることから、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;
4

1 に答える 1

0

他に何かが起こっています。おそらく、トリガーまたは非効率的なインデックスがあるため、個々の更新にそれぞれ多くの時間がかかっていると思われます。(各ステートメントが個別に高価である場合、実際の作業に比べてコンテキストの切り替えが無視できるため、一括更新を使用しても多くの時間を節約できないことに注意してください)。

これが私のテスト設定です:

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;
/

目立たないテスト マシンで約 1.5 秒で 100000 行が更新されました。同じデータ セットを行ごとに更新するには、約 4 秒かかります。

新しく作成したテーブルで同様のスクリプトを実行できますか?

于 2012-03-08T13:32:07.827 に答える