4

読みやすくするために、テーブル/フィールド名などを変更したことに注意してください。元の名前のいくつかは非常に紛らわしいです。

私は3つの異なるテーブルを持っています:

Retailer (Id+Code is a unique key)
- Id
- Code
- LastReturnDate
- ...

Delivery/DeliveryHistory (combination of Date+RetailerId is unique)
- Date
- RetailerId
- HasReturns
- ...

DeliveryDeliveryHistoryほぼ同じです。データは定期的に履歴テーブルに移動されますが、これが最後にいつ発生したかを確実に知る方法はありません。一般に、配信テーブルは非常に小さく (通常は 100,000 行未満)、履歴テーブルには通常数百万行あります。

私の仕事は、DeliveryまたはDeliveryHistoryで真でLastReturnDateある現在の最高日付値に基づいて、各小売業者のフィールドを更新することです。HasReturns

以前は、次のように定義されたビューで解決されていました。

SELECT Id, Code, MAX(Date) Date
   FROM Delivery
   WHERE HasReturns = 1
   GROUP BY Id, Code
UNION
SELECT Id, Code, MAX(Date) Date
   FROM DeliveryHistory
   WHERE HasReturns = 1
   GROUP BY Id, Code

そして、次の UPDATE ステートメント:

UPDATE Retailer SET LastReturnDate = (
    SELECT MAX(Date) FROM DeliveryView
    WHERE Retailer.Id = DeliveryView.Id AND Retailer.Code = DeliveryView.Code)
WHERE Code = :Code AND EXISTS (
    SELECT * FROM DeliveryView
    WHERE Retailer.Id = DeliveryView.Id AND Retailer.Code = DeliveryView.Code
    HAVING
        MAX(Date) > LastReturnDate OR
        (LastReturnDate IS NULL AND MAX(Date) IS NOT NULL))

EXISTS 句は、現在の値が新しい値よりも大きいフィールドの更新を防ぎますが、通常のプログラムの実行中にどのように発生するかを確認するのは難しいため、これは実際には重大な問題ではありません。AND Max(Date) IS NOT NULLまた、DeliveryView で Date を null にすることは不可能であるため、この部分が実際には不要であることに注意してください。しかし、EXISTS 句は、実際にはパフォーマンスをわずかに改善するように見えます。

ただし、UPDATE のパフォーマンスは最近ひどいものになっています。Retailer テーブルに 1000 ~ 2000 の関連エントリしか含まれていないデータベースでは、UPDATE の実行に 5 分以上かかっています。EXISTS 句全体を削除しても、つまり次の非常に単純なステートメントを使用しても、これが行われることに注意してください。

UPDATE Retailer SET LastReturnDate = (
    SELECT MAX(Date) FROM DeliveryView
    WHERE Retailer.Id = DeliveryView.Id AND Retailer.Code = DeliveryView.Code)
WHERE Code = :Code

したがって、私はより良い解決策を探してきました。私の最初のアイデアは、一時テーブルを作成することでしたが、しばらくして MERGE ステートメントとして記述しようとしました。

MERGE INTO Retailer
USING (SELECT Id, Code, MAX(Date) Date FROM DeliveryView GROUP BY Id, Code)
    ON (Retailer.Id = DeliveryView.Id AND Retailer.Code = DeliveryView.Code)
WHEN MATCHED THEN
    UPDATE SET LastReturnDate = Date WHERE Code = :Code

これは機能しているようで、UPDATE よりも 1 桁以上高速です。

3 つの質問があります。

  1. これは、すべてのケースで UPDATE と同じ効果があると確信できますか (LastReturnDate が既に MAX(Date) よりも大きいというエッジ ケースを無視します)。
  2. なぜそんなに速いのですか?
  3. より良い解決策はありますか?

クエリ プラン

マージプラン

コスト: 25,831、バイト: 1,143,828

分かりやすい言葉

  1. テーブル SCHEMA.Delivery のすべての行が読み取られます。
  2. 行は、グループ化するために並べ替えられました。
  3. テーブル SCHEMA.DeliveryHistory のすべての行が読み取られます。
  4. 行は、グループ化するために並べ替えられました。
  5. 重複する行を含め、手順 2、4 からすべての行を返します。
  6. 手順 5 の行は、重複行を排除するために並べ替えられました。
  7. ビュー定義は、保存されたビュー SCHEMA.DeliveryView から、または手順 6 で定義されたとおりに処理されました。
  8. 行は、グループ化するために並べ替えられました。
  9. 保存されたビュー SCHEMA からのビュー定義が処理されました。または手順 8 で定義されているとおり。
  10. テーブル SCHEMA.Retailer のすべての行が読み取られます。
  11. 手順 9、10 の結果セットが結合されました (ハッシュ)。
  12. 保存されたビュー SCHEMA からのビュー定義が処理されました。または手順 11 で定義されているとおり。
  13. 行がマージされました。
  14. 行がリモートでマージされました。

テクニカル

Plan                                            Cardinality Distribution
14 MERGE STATEMENT REMOTE  ALL_ROWS
Cost: 25 831  Bytes: 1 143 828                                              3 738   
    13 MERGE SCHEMA.Retailer ORCL                                           
        12 VIEW SCHEMA.                                         
            11 HASH JOIN  
            Cost: 25 831  Bytes: 1 192 422                                  3 738   
                9 VIEW SCHEMA. 
                Cost: 25 803  Bytes: 194 350                            7 475   
                    8 SORT GROUP BY  
                    Cost: 25 803  Bytes: 194 350                        7 475   
                        7 VIEW VIEW SCHEMA.DeliveryView ORCL
                        Cost: 25 802  Bytes: 194 350                    7 475   
                            6 SORT UNIQUE  
                            Cost: 25 802  Bytes: 134 550                7 475   
                                5 UNION-ALL                 
                                    2 SORT GROUP BY  
                                    Cost: 97  Bytes: 25 362         1 409   
                                        1 TABLE ACCESS FULL TABLE SCHEMA.Delivery [Analyzed] ORCL
                                        Cost: 94  Bytes: 210 654    11 703  
                                    4 SORT GROUP BY  
                                    Cost: 25 705  Bytes: 109 188        6 066   
                                        3 TABLE ACCESS FULL TABLE SCHEMA.DeliveryHistory [Analyzed] ORCL
                                        Cost: 16 827  Bytes: 39 333 636     2 185 202   
                10 TABLE ACCESS FULL TABLE SCHEMA.Retailer [Analyzed] ORCL
                Cost: 27  Bytes: 653 390                            2 230

UPDATEプラン

コスト: 101,492、バイト: 272,060

分かりやすい言葉

  1. テーブル SCHEMA.Retailer のすべての行が読み取られます。
  2. インデックス SCHEMA.DeliveryHasReturns を使用して 1 つ以上の行が取得されました。インデックスは昇順でスキャンされました。
  3. テーブル SCHEMA.Delivery の行は、インデックスから取得した行 ID を使用してアクセスされました。
  4. 行は、グループ化するために並べ替えられました。
  5. インデックス SCHEMA.DeliveryHistoryHasReturns を使用して 1 つ以上の行が取得されました。インデックスは昇順でスキャンされました。
  6. テーブル SCHEMA.DeliveryHistory の行は、インデックスから取得した行 ID を使用してアクセスされました。
  7. 行は、グループ化するために並べ替えられました。
  8. 重複する行を含め、手順 4、7 からすべての行を返します。
  9. 手順 8 の行は、重複行を排除するために並べ替えられました。
  10. ビュー定義は、保存されたビュー SCHEMA.DeliveryView から、または手順 9 で定義されたとおりに処理されました。
  11. 行は、グループ化するために並べ替えられました。
  12. 保存されたビュー SCHEMA からのビュー定義が処理されました。または手順 11 で定義されているとおり。
  13. 行が更新されました。
  14. 行がリモートで更新されました。

テクニカル

Plan                                        Cardinality Distribution
14 UPDATE STATEMENT REMOTE  ALL_ROWS
Cost: 101 492  Bytes: 272 060                                       1 115   
    13 UPDATE SCHEMA.Retailer ORCL                                      
        1 TABLE ACCESS FULL TABLE SCHEMA.Retailer [Analyzed] ORCL
        Cost: 27  Bytes: 272 060                                1 115   
        12 VIEW SCHEMA. 
        Cost: 90  Bytes: 52                                 2   
            11 SORT GROUP BY  
            Cost: 90  Bytes: 52                             2   
                10 VIEW VIEW SCHEMA.DeliveryView ORCL
                Cost: 90  Bytes: 52                         2   
                    9 SORT UNIQUE  
                    Cost: 90  Bytes: 36                     2   
                        8 UNION-ALL                     
                            4 SORT GROUP BY  
                            Cost: 15  Bytes: 18             1   
                                3 TABLE ACCESS BY INDEX ROWID TABLE SCHEMA.Delivery [Analyzed] ORCL
                                Cost: 14  Bytes: 108        6   
                                    2 INDEX RANGE SCAN INDEX SCHEMA.DeliveryHasReturns [Analyzed] ORCL
                                    Cost: 2     12  
                            7 SORT GROUP BY  
                            Cost: 75  Bytes: 18             1   
                                6 TABLE ACCESS BY INDEX ROWID TABLE SCHEMA.DeliveryHistory [Analyzed] ORCL
                                Cost: 74  Bytes: 4 590          255 
                                    5 INDEX RANGE SCAN INDEX SCHEMA.DeliveryHistoryHasReturns [Analyzed] ORCL
                                    Cost: 6     509
4

0 に答える 0