3

したがって、私のデータベースには、多対 1 の関係を持つ 2 つのテーブルがあります。「子」テーブルのすべての行を調べて (ここで正しい用語を使用していない場合は申し訳ありません)、更新する値を決定するためにデータにさまざまなルールのセットを適用して、「親」テーブルを更新しようとしています。と。しかし、私はこれを効率的に (つまり、迅速に) 行いたいと考えています。

したがって、次の表を想定してください。

PARENT(
    ID                                 NUMBER,
    NAME                               VARCHAR(20),
    NUMBER_OF_CHILDREN                 NUMBER,
    AVERAGE_CHILD_AGE                  NUMBER,
    OLDEST_CHILD_AGE                   NUMBER,
    YOUNGEST_CHILD_AGE                 NUMBER,
    MODE_EYE_COLOR                     VARCHAR(20),
    EVERY_CHILD_MADE_A                 VARCHAR(1),
    BLOODTYPES_THAT_CAN_BE_ACCEPTED    VARCHAR(100),
    SOMETHING_COMPLEX                  COMPLEX_OBJECT_1
)

CHILD(
    ID                   NUMBER,
    PARENT_ID            NUMBER,
    AGE                  NUMBER,
    EYE_COLOR            VARCHAR(20),
    MADE_AN_A            VARCHAR(1),
    BLOODTYPE            VARCHAR(5),
    COMPLEXITY           COMPLEX_OBJECT_2
)

簡単な例を使用しましたが、適用する必要がある実際のルールは、最小/最大/平均よりもかなり複雑です。さて、これらは、これを行うことができると私が考えている2つの方法です。1 つ目は、プロシージャに親 ID を関数に渡すだけで (私は別の関数を使用しているので、後で戻ってこのコードを維持する方が簡単です)、それぞれが子を選択して処理します。2 番目の方法は、子を選択するカーソルを開き、カーソルを各関数に渡すことです。

PROCEDURE UPDATE_PARENT_1 (PARENT_ID IN NUMBER)
BEGIN
    UPDATE PARENT
    SET
        NUMBER_OF_CHILDREN                = CHILD_COUNT_FUNCTION(PARENT_ID),
        AVERAGE_CHILD_AGE                 = CHILD_AGE_AVERAGE_FUNCTION(PARENT_ID),
        OLDER_CHILD_AGE                   = PICK_OLDEST_AGE_FUNCTION(PARENT_ID),
        YOUNGEST_CHILD_AGE                = PICK_YOUNGEST_AGE_FUNCTION(PARENT_ID),
        MODE_EYE_COLOR                    = MOST_OFTEN_EYE_COLOR_FUNCTION(PARENT_ID),
        BLOODTYPES_THAT_CAN_BE_ACCEPTED   = DETERMINE_BLOOD_DONOR_TYPES(PARENT_ID),
        SOMETHING_COMPLEX                 = COMPLEX_FUNCTION(PARENT_ID)
    WHERE
        ID = PARENT_ID;
END;


PROCEDURE UPDATE_PARENT_2 (PARENT_ID IN NUMBER)
    CURSOR C IS SELECT * FROM CHILD WHERE CHILD.PARENT_ID = PARENT_ID
BEGIN
    OPEN C;

    UPDATE PARENT
    SET
        NUMBER_OF_CHILDREN                = CHILD_COUNT_FUNCTION(C),
        AVERAGE_CHILD_AGE                 = CHILD_AGE_AVERAGE_FUNCTION(C),
        OLDER_CHILD_AGE                   = PICK_OLDEST_AGE_FUNCTION(C),
        YOUNGEST_CHILD_AGE                = PICK_YOUNGEST_AGE_FUNCTION(C),
        MODE_EYE_COLOR                    = MOST_OFTEN_EYE_COLOR_FUNCTION(C)
        BLOODTYPES_THAT_CAN_BE_ACCEPTED   = DETERMINE_BLOOD_DONOR_TYPES(C),
        SOMETHING_COMPLEX                 = COMPLEX_FUNCTION(C)
    WHERE
        ID = PARENT_ID;

    CLOSE C;
END;

どちらにしても余計なことをしているような気がします。最初の方法は、あまりにも多くの select ステートメントを実行しているように見えるため、気分が悪くなります (適用する必要があるルールごとに 1 つで、多数あります)。2番目の方法は、別の選択を行うのではなく、カーソルの前に戻るだけですが、もっと効率的な方法があるはずだと感じています。同時に、オラクルは舞台裏で優れた最適化を行っているため、どちらの方法も舞台裏で最適な方法で最適化されている可能性があります。

だから私の質問は、この種の更新を行うための最も速い方法は何ですか?それとも、最適化について心配する必要はありませんか?

編集:例をもう少し複雑にしました。

4

3 に答える 3

2

まず、エド・ギブの答えから恥知らずに借りています。私の唯一の追加は、モードを取得する方法を示すことです。

これを行うために、集計の代わりに分析関数を使用しています。新しい列のほとんどは同じで、over (partition by parent_id)節があるだけです。最も内側のサブクエリには、特定の目の色を持つ子供の数も含まれます。サブクエリの次のレベルはその値で順序付けされ、最も外側の行がモードを持つ行の 1 つを選択します。

UPDATE Parent
    SET (Number_Of_Children, Average_Child_Age, Oldest_Child_Age, Youngest_Child_Age
         Mode_Eye_Color) =
         (select cnt, avg_age, min_age, max_age, eyecolor 
          from (select cnt, avg_age, min_age, max_age, eyecolor
                       ROW_NUMBER() over (order by cnt_ec desc) as seqnum
                from (select COUNT(*) over (partition by Parent_id) as cnt,
                             AVG(Age) over (partition by Parent_id) as avg_age,
                             MIN(Age) over (partition by Parent_id) as min_age,
                             MAX(Age) over (partition by Parent_id) as max_age,
                             COUNT(*) over (partition by Parent_id, eyecolor) as cnt_ec,
                             eyecolor
                      from Child
                      where Parent.ID = Child.Parent_ID
                     ) t
               ) t
          where seqnum = 1
         )
于 2013-05-17T17:57:22.440 に答える