7

データベースには、30 列の 2 つのテーブルを where 条件で結合してテーブルを更新するストアド プロシージャがあります。SQL の一般的な形式は次のとおりです。

UPDATE Target
SET col1 = Source.col1
INNER JOIN Source 
on 
ISNULL(Target.Col2, '') = ISNULL(Source.Col2, '') and
ISNULL(Target.Col3, '') = ISNULL(Source.Col3, '') and
.
.
.
ISNULL(Target.Col31, '') = ISNULL(Source.Col31, '') and 

これがクエリプランです。それを PC に保存し、再度開くと、より適切にスケーリングされます。

ここに画像の説明を入力

ソース テーブルには 65M のレコードがあり、ターゲットには 165M のレコードがあります。以前は、かなりの数分で実行されていました。クエリがどれほど醜く、潜在的に非効率的であるかを考えると、これは驚くべきことです。今月は 1.5 時間実行され、プロセッサが 100% 使用されたため、強制終了する必要がありました。

以下のクエリを即興で実行し、時間通りに実行する方法について何か提案はありますか?

30 列の結合条件で使用されるいくつかの列に単一列のインデックスがあります。

私は ISNULL 関数と 30 列の結合がおかしいことを知っています。これは悪い設計です。私を責めないでください、私はこの経済を継承しました。

残念ながら、再設計の時間はありません。助言がありますか?

4

2 に答える 2

5
  1. 推定実行計画のスクリーンショットを投稿してください
  2. 以前はクエリでハッシュ結合が使用されていたと思われますが (そうすべきです)、どういうわけかカーディナリティの推定が間違っていて、ループ結合が発生します。クエリにハッシュ結合ヒントを適用して、これが修正されたかどうかを確認します ( INNER HASH JOIN)。正確な計画ができたら、もっと話すことができます。
  3. 等号を に変更し(A1 = A2 OR (A1 IS NULL AND A2 IS NULL))ます。SQL Server は実際にこのパターンを認識し、内部的に「愚かな null セマンティクスのない正確な等号」に変換します。null 値を使用しても、そのようにインデックスをシークできます。

これで問題が解決しない場合は、手順 (3) を実行して、col1 を含む col2-col31 にカバリング インデックスを作成してください。これにより、この場合に可能な最も効率的な計画であるマージ結合が得られます。本当に速いです。警告: これにより、テーブルのディスク上のサイズが 2 倍になり、更新が遅くなります。

于 2012-05-02T22:05:28.357 に答える
0

DBa は、クエリ アナライザーの推奨事項に従って、30 列すべてにインデックスを追加することを提案しました。ほとんどの列は「含まれる」列でした。これにより、クエリが完了しました。実行した翌月、通常 1.5 時間で実行される同じ更新 SQL が 24 時間で完了しませんでした。Update statistics を実行すると、1 時間で完了しました。

于 2012-06-10T04:51:36.860 に答える