这是SQL Server 2008中我有这两个表和联接:Sql Server的意外笛卡尔乘积
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
第一个表有5680行(每一个员工在一个范围内的每个日期),该第二个有397个(员工实际工作的每一天有一个或多个)。 (因此,EmployeeId/WorkDate是第一个表中的唯一组合,但不是第二个表中的组合)。我的查询结果是正确的(每个员工列出每天有一行或多行的工作天数和一行他没有工作),但大约需要3秒钟,而我的个人资料显示沿途有笛卡儿积(2,254,960行)。有没有办法重构此查询以防止完整的交叉连接?
* EDITED * 添加主键之后,所建议的,集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][email protected][EmployeeId] as [ecd].[EmployeeId] AND @ET.[WorkDate] as [et].[WorkDate][email protected][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][email protected][ServiceCallId] as [et].[ServiceCallId]) ORDERED FORWARD)
我的意思是什么“显示沿途笛卡尔积”来自设定统计个人资料。它在这里显示的太多了,但是对于计划中的最后一项(Clustered Index Scan),它在行下显示2,254,960(我的逗号),在执行下显示5680。我误解说我有笛卡尔产品吗?
为每个表添加一个主键? –
我在第一个表中添加了'PRIMARY KEY(EmployeeId,WorkDate)',并且在第二个表中添加了'EmployeeTimeId UNIQUEIDENTIFIER PRIMARY KEY'。我的执行时间降到了亚秒,这太棒了(谢谢!),但笛卡儿临时产品仍然存在!有点让它很难担心,呵? –
你尝试过使用查询提示吗?在查询结尾添加“Option(HASH JOIN,MERGE JOIN)”。 –