I have a query that basically looks like this:
Select *
From UserSearches us
left outer join Quotes q on q.UserSearchId = us.Id and q.QuoteNumber is not null
left outer join ContainerDetails cd on cd.QuoteId = q.Id
left outer join Surcharges s on s.ContainerDetailId = cd.Id
where us.SearchDate between @beginDate and @endDate
Given certain values of @beginDate and @endDate, I have a search that takes 30 seconds to return around 100K rows.
The ultimate goal is to populate some objects that have parent-child-child-child relationships. So after some experimentation, I found that I could speed up the query dramatically with the following:
Select *
From UserSearches us
left outer join Quotes q on q.UserSearchId = us.Id and q.QuoteNumber is not null
left outer join ContainerDetails cd on cd.QuoteId = q.Id
where us.SearchDate between @beginDate and @endDate
Select cd.Id into #cdIds
From UserSearches us
left outer join Quotes q on q.UserSearchId = us.Id and q.QuoteNumber is not null
left outer join ContainerDetails cd on cd.QuoteId = q.Id
where us.SearchDate between @beginDate and @endDate
Select * From Surcharges s
inner join #cdIds on s.ContainerDetailId = #cdIds.Id
DROP TABLE #cdIds
This runs in 10 seconds, which makes no sense to me. Surely it should be faster just to join the Surcharges in the first place.
The Surcharge table has the following indexes:
PK:
ALTER TABLE [dbo].[Surcharges] ADD CONSTRAINT [PK_dbo.Surcharges] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
IX1:
CREATE NONCLUSTERED INDEX [IX_Surcharge_ContainerDetailId] ON [dbo].[Surcharges]
(
[ContainerDetailId] ASC
)
INCLUDE ( [Id],
[Every],
[Single],
[Column],
[About],
[Twelve],
[Of],
[Them],
)
IX2:
CREATE NONCLUSTERED INDEX [IX_ContainerDetailId] ON [dbo].[Surcharges]
(
[ContainerDetailId] ASC
)
To sum up, why is it faster to do a separate query for my Surcharges than it is to join them in the first place?
EDIT: Here are the execution plans. These are .sqlplan files that you can open in Sql Studio: