sql >> データベース >  >> RDS >> Oracle

MERGEクエリを改善する方法はありますか?

    大規模がある場合 アプローチに問題がある場合は、clean.id列のインデックスが欠落している可能性があります。 、MERGEの場合のアプローチに必要です dualを使用します 各行のソースとして。

    idを言っている間、これは起こりそうにありません。 主キーです 。

    したがって、基本的に あなたは正しい考えをしていて、実行計画 が表示されます。 以下のようなものです:

    ---------------------------------------------------------------------------------------------------
    | Id  | Operation                       | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
    ---------------------------------------------------------------------------------------------------
    |   0 | MERGE STATEMENT                 |                 |       |       |     2 (100)|          |
    |   1 |  MERGE                          | CLEAN           |       |       |            |          |
    |   2 |   VIEW                          |                 |       |       |            |          |
    |   3 |    NESTED LOOPS OUTER           |                 |     1 |    40 |     2   (0)| 00:00:01 |
    |   4 |     TABLE ACCESS FULL           | DUAL            |     1 |     2 |     2   (0)| 00:00:01 |
    |   5 |     VIEW                        | VW_LAT_A18161FF |     1 |    38 |     0   (0)|          |
    |   6 |      TABLE ACCESS BY INDEX ROWID| CLEAN           |     1 |    38 |     0   (0)|          |
    |*  7 |       INDEX UNIQUE SCAN         | CLEAN_UX1       |     1 |       |     0   (0)|          |
    ---------------------------------------------------------------------------------------------------
     
    Predicate Information (identified by operation id):
    ---------------------------------------------------
     
       7 - access("CLEAN"."ID"=:ID)
    

    したがって、実行計画は問題なく効果的に機能しますが、問題が1つあります。

    常にインデックスを使用することを忘れないでください。数行を処理していても問題はありませんが、スケーリングは行われません

    数百万を処理している場合 レコードの場合、2段階の処理にフォールバックできます。

    • 一時テーブルにすべての行を挿入します

    • 単一のMERGEを実行します 一時テーブルを使用したステートメント

    大きな利点 Oracleはhash joinを開くことができるということです millionごとにインデックスアクセスを削除します 行。

    ここにcleanのテストの例があります 1Mのidで開始されたテーブル (図には示されていません)および1M挿入と1M更新の実行:

    n  = 1000000
    data2 = [{"id" : i, "xcount" :1} for i in range(2*n)]  
    
    sql3 = """
        insert into tmp (id,count)
        values (:id,:xcount)"""
    sql4 = """MERGE into clean USING tmp on (clean.id = tmp.id)
              when not matched then insert (id, count)  values (tmp.id, tmp.count)
              when matched then update set clean.count= clean.count + tmp.count"""    
    
    cursor.executemany(sql3, data2)
    cursor.execute(sql4)
    

    テストは約で実行されます。 10秒、これはMERGEでアプローチする半分未満です dualを使用する 。

    それでも不十分な場合は、並列オプションを使用する必要があります。 。



    1. SQL ServerでのROW_NUMBER()のしくみ

    2. データベースへのアクセスを無効にする

    3. PostgreSQLの実行速度が遅い?ソースに到達するためのヒントとコツ

    4. 時間に基づいて2つのテーブルをマージします