まず、背景をいくつか。
スタッフが注文に関する請求データをアプリに入力し、それをSQL Server 2000データベースに保存する注文処理システムがあります。このデータベースは実際の課金システムではありません。夜間のバッチ プロセスを介してレコードをメインフレーム システムに実行できるようにするための保管場所にすぎません。
このバッチ プロセスは、外部ベンダーが提供する缶詰のサード パーティ パッケージです。その役割の一部は、拒否されたすべてのレコードのレポートを提供することです。拒否レポートは手動で処理されます。
残念ながら、サードパーティのソフトウェアはすべてのエラーをキャッチできないことが判明しました。メインフレームからデータベース内の別のテーブルにデータをプルバックし、拒否された料金をさらに別のテーブルにロードする別のプロセスがあります。
次に監査プロセスが実行され、スタッフが最初に入力したすべての内容がどこかで説明できるようになります。この監査は、実行する SQL クエリの形式をとり、次のようになります。
SELECT *
FROM [StaffEntry] s with (nolock)
LEFT JOIN [MainFrame] m with (nolock)
ON m.ItemNumber = s.ItemNumber
AND m.Customer=s.Customer
AND m.CustomerPO = s.CustomerPO -- purchase order
AND m.CustPORev = s.CustPORev -- PO revision number
LEFT JOIN [Rejected] r with (nolock) ON r.OrderID = s.OrderID
WHERE s.EntryDate BETWEEN @StartDate AND @EndDate
AND r.OrderID IS NULL AND m.MainFrameOrderID IS NULL
もちろん大幅に修正されていますが、重要な部分は表現されていると思います。問題は、このクエリの実行に時間がかかりすぎていることです。私はそれを高速化する方法を見つけようとしています。
StaffEntry
問題は、テーブルからテーブルへのJOIN であると確信していMainFrame
ます。どちらも当初 (このシステムでは 2003 年) からのすべての注文のデータを保持しているため、少し大きくなる傾向があります。テーブルで使用されているOrderID
との値は、メインフレームにインポートされたときに保持されません。そのため、その結合はもう少し複雑になります。そして最後に、存在しないテーブル内のレコードを探しているので、JOIN を実行した後、where 句に醜いものがあります。EntryDate
StaffEntry
MainFrame
IS NULL
このStaffEntry
テーブルは、EntryDate (クラスター化) によって索引付けされ、Customer/PO/rev で個別に索引付けされます。 MainFrame
顧客とメインフレームの課金番号 (クラスタ化されている、これは他のシステムに必要) によって索引付けされ、顧客/PO/Rev ごとに個別に索引付けされます。 Rejected
はまったく索引付けされていませんが、サイズは小さく、テストでは問題ではないことが示されています。
それで、その関係を表現できる別の(できればもっと速い)方法があるかどうか疑問に思っていますか?