3

毎月、自分のオラクル データベースで簡単な更新ステートメントを実行しています。しかし、月曜日から非常に時間がかかります。テーブルは毎月 5% ずつ増加します。現在、800 万件のレコードが保存されています。

声明:

update /*+ parallel(destination_tab, 4) */ destination_tab dest    
   set (full_name, state) =   
       (select /*+ parallel(source_tab, 4) */ dest.name, src.state   
        from source_tab src   
        where src.city = dest.city);

実際には、2 つだけでなく 20 のフィールドを更新する必要があります...しかし、問題を説明するのは簡単に見えます。

計画を説明する:

-----------------------------------------------------------------------------------------------------                               
| Id  | Operation                    | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |                                   
-----------------------------------------------------------------------------------------------------                               
|   0 | update statement             |                      |  8517K|  3167M|   579M (50)|999:59:59 |                                   
|   1 |  update                      | destination_tab      |       |       |            |          |
|   2 |   PX COORDINATOR             |                      |       |       |            |          |
|   3 |    PX SEND QC (RANDOM)       | :TQ10000             |  8517K|  3167M|  6198   (1)| 00:01:27 |
|   4 |     px block iterator        |                      |  8517K|  3167M|  6198   (1)| 00:01:27 |
|   5 |      table access full       | DESTINATION_TAB      |  8517K|  3167M|  6198   (1)| 00:01:27 |
|   6 |   table access by index rowid| SOURCE_TAB           |     1 |    56 |     1   (0)| 00:00:01 |
|*  7 |    index unique scan         | CITY_PK              |     1 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------

どうしてこれができるのか、誰か私に説明してもらえますか? 計画は非常に悪いようです!本当にありがとう。

4

4 に答える 4

1

どのくらいの長さが長すぎるとは言いませんでした。800 万行のテーブルに参加しています。source_tab に何行あるかわかりません。

実行計画が、destination_tab の完全なテーブル スキャンを示していることに気付きました。destination_tab テーブルの都市列はインデックス化されていますか? そうでない場合は、インデックスを追加してみてください。そうである場合、Oracle はそれを無視している可能性があります。これは、とにかくすべての値を返す必要があり、destination_tab が駆動テーブルであることを認識しているためです。

どのように最適化しても、テーブルが大きくなるにつれて常にパフォーマンスが低下します。これは、別のテーブルに結合された同じテーブルから値をフェッチしてすべての行を更新しているためです。つまり、N が destination_tab の行数である場合、常に N 操作を実行します。

高レベルの質問/提案:

  1. 毎回すべての行を更新する必要がありますか? 値が変更されている可能性が高いのは特定の行だけですか? もしそうなら、どの行を更新する必要があるかをどうにかして予測し、更新をそれに制限できますか。
  2. なぜそこにヒントがあるのですか?パフォーマンスが変化した場合は、ヒントをドロップして実験します。最適なプランを見つけるのがオプティマイザーの仕事です。ヒントを使用することで、オプティマイザにジョブの実行方法を伝えます。あなたは正しいほうがいい。
  3. destination_tab の full_name 列を同じ行の name 列に更新しています。ただし、テーブルへの結合を通じて name 列を取得しています。あなたの選択からそれを取り出して、以下のようなものを使用する方が速いかもしれません. これは推測です。それは問題ではないかもしれません。

    update destination_tab dest    
     set full_name = name,
       state = 
       (select src.state   
        from source_tab src   
        where src.city = dest.city);
    
于 2013-03-17T16:51:08.783 に答える
1

以下を試してください。

merge
 into destination_tab d
using source_tab      s
   on (d.city = d.city)
when matched then
   update 
      set d.state = s.state
    where decode(d.state, s.state, 1, 0) = 0;
于 2013-03-17T22:05:42.597 に答える
1

これがデータ ウェアハウスの場合、特に大きなテーブルのすべての行ではなく、更新を行いません。おそらく、さまざまなベーステーブルの断片を組み合わせてマテリアライズドビューを作成し、必要に応じて完全に更新します(非アトミック:切り捨て+挿入追加)。

編集:現在の更新アプローチが通常よりもはるかに時間がかかっている理由については、私の推測では、以前の実行でOracleはバッファキャッシュで更新に必要なかなりの数のブロックを見つけ、最近Oracleはディスクから多くを取得する必要がありました最初にバッファします。一貫性のある取得と db ブロックの取得 (論理 io) と物理 io (ディスク) を調べることができます。

于 2013-03-17T18:32:12.963 に答える
0

データ ウェアハウスの感覚などについてのコメントは理解できます。ただし、この種の更新を行う必要があります。更新は ETL ワークフローの一部です。テーブル「宛先」の完全な 800 万レコードを毎月コピーする必要があります。この手順の後、UPDATE を実行する必要があり、問題が発生します。

日々のパフォーマンスが非常に悪いという問題が理解できません。通常、更新は 45 分間実行されます。今、それは約4時間実行されます。しかし、なぜ?ソートの必要がないため、有名な理由である「メイン メモリではなくディスクでソートする」ことはできません。私の場合の問題は何ですか?

通常の更新 (方法) とマージ更新のパフォーマンスに違いはありますか?

于 2013-03-17T21:53:08.733 に答える