2

これは SQL Server 2008 です。次の 2 つのテーブルと結合があります。

DECLARE @EmployeeCrossDay TABLE
(
    EmployeeId UNIQUEIDENTIFIER, 
    WorkDate DATE, OtherStuff...
)

DECLARE @ET TABLE
(
    EmployeeId      UNIQUEIDENTIFIER,
    WorkDate        DATE, DifferentOtherStuff...
)

SELECT *
FROM @EmployeeCrossDay ecd
LEFT JOIN @ET et ON et.EmployeeId = ecd.EmployeeId
    AND et.WorkDate = ecd.WorkDate 

最初のテーブルには 5,680 行 (範囲内の各日付の従業員ごとに 1 行)、2 番目のテーブルには 397 行 (従業員が実際に働いた日ごとに 1 行以上) があります。(したがって、EmployeeId/WorkDate は、最初のテーブルでは一意の組み合わせですが、2 番目のテーブルではそうではありません。) クエリの結果は正しいです (各従業員のリストには、勤務した日の 1 つ以上の行と、各日の行があります)。彼はうまくいきませんでした)、しかしそれには約 3 秒かかり、私のプロファイルは途中でデカルト積を示しています (2,254,960 行)。完全なクロス結合を防ぐためにこのクエリを再構築する方法はありますか?

*編集済み* 主キーを追加した後、提案されているように、Showplan_Textをオンに設定すると、次のようになります。

  |--Compute Scalar(DEFINE:([Expr1007]=isnull(@ET.[StartTime] as [et].[StartTime],[Expr1010]), [Expr1008]=isnull(@ET.[EndTime] as [et].[EndTime],[Expr1010])))
       |--Nested Loops(Left Outer Join, OUTER REFERENCES:([et].[ServiceCallId]))
            |--Compute Scalar(DEFINE:([Expr1006]=isnull(@ET.[TypeId] as [et].[TypeId],(8)), [Expr1009]=isnull(@ET.[Interrupt] as [et].[Interrupt],($0.0000))))
            |    |--Nested Loops(Left Outer Join, WHERE:(@ET.[EmployeeId] as [et].[EmployeeId]=@EmployeeCrossDay.[EmployeeId] as [ecd].[EmployeeId] AND @ET.[WorkDate] as [et].[WorkDate]=@EmployeeCrossDay.[WorkDate] as [ecd].[WorkDate]))
            |         |--Compute Scalar(DEFINE:([Expr1010]=CONVERT_IMPLICIT(datetime,@EmployeeCrossDay.[WorkDate] as [ecd].[WorkDate],0)))
            |         |    |--Sort(ORDER BY:([ecd].[Number] ASC, [ecd].[WorkDate] ASC))
            |         |         |--Clustered Index Scan(OBJECT:(@EmployeeCrossDay AS [ecd]))
            |         |--Clustered Index Scan(OBJECT:(@ET AS [et]))
            |--Clustered Index Seek(OBJECT:([Snapper].[dbo].[ServiceCalls].[PK_Jobs] AS [sc]), SEEK:([sc].[ServiceCallId]=@ET.[ServiceCallId] as [et].[ServiceCallId]) ORDERED FORWARD)

「途中でデカルト積を表示する」とは、Statistics Profile をオンに設定することに由来します。ここに貼り付けるには多すぎますが、プランの最後から 2 番目の項目 (クラスター化インデックス スキャン) では、行の下に 2,254,960 (私のコンマ)、実行の下に 5680 が表示されます。私はデカルト積を持っていると誤解していますか?

4

1 に答える 1

1

私は3つの良い答えを得ましたが、それらはすべてコメントとして来たので、ここに「その」答えを投稿しています.

Aaron は、各テーブル変数に主キーを追加することを提案しました。追加した

EmployeeTimeId  UNIQUEIDENTIFIER PRIMARY KEY

@ET へ

PRIMARY KEY (EmployeeId, WorkDate)

どちらの場合も EmployeeId が一意ではなかったためです。

EmpmloyeeTimeId は結合に関与していませんでしたが、これだけでクエリが 3 秒超から 1 秒未満に短縮されました。しかし、私の統計プロファイルは、実行計画のステップの 1 つが 5680 回実行され、220 万行 (5,680 * 397)。応答時間は許容範囲内でしたが、私はそれについて興味がありました.

その後、Martin は、@ET のキーは EmployeeId を先導する必要があると提案しました。だから私はキーを

PRIMARY KEY( EmployeeId, EmployeeTimeId )

この時点で、実行計画は、以前のクロス結合が (200 万を超える代わりに) 397 行にまで減少したことを示していました。各 @ET 行 (5680) に対してプロセスを実行していたにもかかわらず、現在はクラスター化インデックスを実行していました。フル テーブル スキャンの代わりにシークします。

途中で、ゴードンは追加を提案しました

OPTION( HASH JOIN, MERGE JOIN )

以前に適用したすべてのインデックスを削除し、結果のプランのステップを 2 回以上実行しませんでした。

3 つの提案はすべて 1 秒以内に同じデータを返したので、それぞれにポイントを与えました (そして今では感謝しています)。

于 2012-06-22T15:54:03.923 に答える