読みやすくするために、テーブル/フィールド名などを変更したことに注意してください。元の名前のいくつかは非常に紛らわしいです。
私は3つの異なるテーブルを持っています:
Retailer (Id+Code is a unique key)
- Id
- Code
- LastReturnDate
- ...
Delivery/DeliveryHistory (combination of Date+RetailerId is unique)
- Date
- RetailerId
- HasReturns
- ...
Delivery
とDeliveryHistory
ほぼ同じです。データは定期的に履歴テーブルに移動されますが、これが最後にいつ発生したかを確実に知る方法はありません。一般に、配信テーブルは非常に小さく (通常は 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 つの質問があります。
- これは、すべてのケースで UPDATE と同じ効果があると確信できますか (LastReturnDate が既に MAX(Date) よりも大きいというエッジ ケースを無視します)。
- なぜそんなに速いのですか?
- より良い解決策はありますか?
クエリ プラン
マージプラン
コスト: 25,831、バイト: 1,143,828
分かりやすい言葉
- テーブル SCHEMA.Delivery のすべての行が読み取られます。
- 行は、グループ化するために並べ替えられました。
- テーブル SCHEMA.DeliveryHistory のすべての行が読み取られます。
- 行は、グループ化するために並べ替えられました。
- 重複する行を含め、手順 2、4 からすべての行を返します。
- 手順 5 の行は、重複行を排除するために並べ替えられました。
- ビュー定義は、保存されたビュー SCHEMA.DeliveryView から、または手順 6 で定義されたとおりに処理されました。
- 行は、グループ化するために並べ替えられました。
- 保存されたビュー SCHEMA からのビュー定義が処理されました。または手順 8 で定義されているとおり。
- テーブル SCHEMA.Retailer のすべての行が読み取られます。
- 手順 9、10 の結果セットが結合されました (ハッシュ)。
- 保存されたビュー SCHEMA からのビュー定義が処理されました。または手順 11 で定義されているとおり。
- 行がマージされました。
- 行がリモートでマージされました。
テクニカル
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
分かりやすい言葉
- テーブル SCHEMA.Retailer のすべての行が読み取られます。
- インデックス SCHEMA.DeliveryHasReturns を使用して 1 つ以上の行が取得されました。インデックスは昇順でスキャンされました。
- テーブル SCHEMA.Delivery の行は、インデックスから取得した行 ID を使用してアクセスされました。
- 行は、グループ化するために並べ替えられました。
- インデックス SCHEMA.DeliveryHistoryHasReturns を使用して 1 つ以上の行が取得されました。インデックスは昇順でスキャンされました。
- テーブル SCHEMA.DeliveryHistory の行は、インデックスから取得した行 ID を使用してアクセスされました。
- 行は、グループ化するために並べ替えられました。
- 重複する行を含め、手順 4、7 からすべての行を返します。
- 手順 8 の行は、重複行を排除するために並べ替えられました。
- ビュー定義は、保存されたビュー SCHEMA.DeliveryView から、または手順 9 で定義されたとおりに処理されました。
- 行は、グループ化するために並べ替えられました。
- 保存されたビュー SCHEMA からのビュー定義が処理されました。または手順 11 で定義されているとおり。
- 行が更新されました。
- 行がリモートで更新されました。
テクニカル
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