我有一个简单的查询,如下所示:
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*"'))
名为Tenants
的表有386533行,Sectors
有40行。我为这两列启用了全文搜索。此查询的执行计划如下:
此查询需要8秒才能运行。但是,当我评论其中一个过滤器时(对于两个过滤器都是如此),它们会立即生效。例如,以下内容立即起作用:
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*"'))
此查询的查询执行计划如下:
我尝试重建索引和统计信息,但没有帮助。另外,我尝试将PK
索引作为提示(因为第二个查询使用它而第一个查询没有),但事情变得更糟。我该怎么做才能加快第一次查询?我不想将查询分成2并将计数加起来(虽然可以立即生效..)
编辑:SQL Server版本为" Microsoft SQL Server 2014 - 12.0.2342.0(X64)"
修改2:客户统计信息:
答案 0 :(得分:2)
在第一种情况下,SQL Server需要执行OUTER JOIN,因为您使用两个表来过滤信息。
在第二种情况下,SQL Server只需要进行INNER JOIN,因为您已经过滤了其中一个表中的信息而您并不关心另一个表,因为这不会影响您的count(*)语句
让我告诉你关于第二种情况的更多细节:
如果按Extend1.Name过滤,则SQL Server不关心Extend2表,因为您已经过滤了信息,而Extend2表不会更改记录数。
如果按Extend2.Name过滤,则SQL Server不需要OUTER JOIN生成的NULL值,这意味着所有记录都已在Extend1表中。 (对于那种情况,你不需要外连接,内部连接就足够了)
(您可以在两个查询计划中看到这一点)
您可以在表Tenants中将SectorId列更改为NOT NULL并指定默认值。之后,您可以将OUTER JOIN更改为INNER JOIN,性能应该更好。
答案 1 :(得分:2)
尝试使用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;
注意:
UNION
,因为这两个查询可能会返回相同的行。. . .
用于标识要计算的每一行的相应列。这是UNION
。JOIN
是内部联接。 WHERE
子句中的条件意味着第二个表中必须存在匹配。