这是 SQL Server 2008。我有这两个表和一个连接:
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 行(一个范围内每个日期的每个员工一个),第二个有 397 行(一个或多个员工实际工作的每一天)。(因此,EmployeeId/WorkDate 是第一个表中的唯一组合,但不是第二个表中的唯一组合。)我的查询结果是正确的(每个员工的列表,其中包含他工作天数的一行或多行,每天一行他没有工作),但这大约需要 3 秒,我的个人资料显示了一个笛卡尔积(2,254,960 行)。有没有办法重组这个查询来防止完全交叉连接?
* EDITED * 按照建议添加主键后,Set Showplan_Text On 给了我这个:
|--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)
我所说的“沿途显示笛卡尔积”的意思来自于设置统计配置文件。它显示的内容太多,无法在此处粘贴,但对于计划中的倒数第二项(聚集索引扫描),它在 Rows 下显示 2,254,960(我的逗号),在 Executes 下显示 5680。我是否误读了说我有笛卡尔积?