Reputation: 5210
I have a simple query like below:
SELECT
COUNT(*)
FROM
[dbo].[Tenants] AS [Extent1]
LEFT OUTER JOIN
[dbo].[Sectors] AS [Extent2] ON [Extent1].[SectorId] = [Extent2].[Id]
WHERE
(CONTAINS([Extent1].[Name], '"asdf*"')) OR
(CONTAINS([Extent2].[Name], '"asdf*"'))
Table named Tenants
has 386533 rows and Sectors
has 40 rows. I have full text search enabled for both of the columns. And the execution plan of this query is below:
This query takes 8 seconds to work. However, when I comment one of the filters out (true for both of the filters), they work instantly. For example, the following works instantly:
SELECT
COUNT(*)
FROM
[dbo].[Tenants] AS [Extent1]
LEFT OUTER JOIN
[dbo].[Sectors] AS [Extent2] ON [Extent1].[SectorId] = [Extent2].[Id]
WHERE
--(CONTAINS([Extent1].[Name], '"asdf*"')) OR
(CONTAINS([Extent2].[Name], '"asdf*"'))
And the query execution plan for this query is below:
I tried rebuilding indexes and statistics but no help. In addition, I tried giving PK
indexes as hint (since the second query uses it whereas the first one doesn't) but made the things worse. What can I do to speed up the first query? I don't want to divide the query into 2 and sum the counts up (that works instantly though..)
Edit: The SQL Server version is "Microsoft SQL Server 2014 - 12.0.2342.0 (X64)"
Edit 2: Client statistics:
Upvotes: 2
Views: 70
Reputation: 2655
In the first case, SQL Server needs to do the OUTER JOIN because you are using both tables to filter the information.
In the second case, SQL Server just needs to do an INNER JOIN because you are already filtering the information in one of the tables and you don't care about the other one because that does not affect your count(*) statement.
Let me give you more detail about the second case:
if you filter by Extend1.Name, SQL Server does not care about the Extend2 table because you already filtered the information and the Extend2 table does not change the count of records.
if you filter by Extend2.Name, SQL Server does not need the NULL values generated by the OUTER JOIN, that means that all the records are already in the Extend1 table. (You don't need an outer join for that case, an inner join is enough)
(You can see this in both query plans)
You can change the column SectorId to NOT NULL in the table Tenants and assign a default value. After that, you can change the OUTER JOIN to INNER JOIN and the performance should be much better.
Upvotes: 2
Reputation: 1270091
Try using UNION
:
SELECT COUNT(*)
FROM ((SELECT . . .
FROM [dbo].[Tenants] [Extent1] LEFT OUTER JOIN
[dbo].[Sectors] [Extent2]
ON [Extent1].[SectorId] = [Extent2].[Id]
WHERE CONTAINS([Extent1].[Name], '"asdf*"')
) UNION
(SELECT . . .
FROM [dbo].[Tenants] [Extent1] INNER JOIN
[dbo].[Sectors] [Extent2]
ON [Extent1].[SectorId] = [Extent2].[Id]
WHERE CONTAINS([Extent2].[Name], '"asdf*"')
)
) x;
Notes:
UNION
because the two queries might return the same rows.. . .
is for the appropriate columns that identify each row you want to count. This is needed for the UNION
.JOIN
is an inner join. The condition in the WHERE
clause means that a match has to exist in the second table.Upvotes: 2