使用横向连接搜索非常慢
Posted
技术标签:
【中文标题】使用横向连接搜索非常慢【英文标题】:Searching with a lateral join extremely slow 【发布时间】:2020-07-01 14:21:22 【问题描述】:我目前正在我们的一个网格中实现搜索功能,这样做时,我的查询从 1 秒或更短的时间运行到大约 16 秒的运行时间(我添加了建议的索引等)。此查询返回的数据将是父母的 id、父母的姓名、最近的孩子的名字和最近的孩子的姓。以下简化查询运行速度极慢(超过 15 秒),但运行正常:
SELECT
p.id
,p.name
,c.firstname
,c.lastname
FROM Parents p
CROSS APPLY (
SELECT TOP (1)
c.firstname
,c.lastname
FROM Children c
WHERE c.ParentId = p.Id
ORDER BY c.datecreated DESC
) i
INNER JOIN Users s
ON p.UserId = u.Id
WHERE (
@search IS NOT NULL
AND @search != ''
AND (
@search = c.firstname
OR @search = c.lastname
OR p.name = @search
)
OR @search IS NULL
OR @search = ''
)
以下查询(注意不包括名字和姓氏搜索)运行速度很快,但缺少所需的功能:
SELECT
p.id
,p.name
,c.firstname
,c.lastname
FROM Parents p
CROSS APPLY (
SELECT TOP (1)
c.firstname
,c.lastname
FROM Children c
WHERE c.ParentId = p.Id
ORDER BY c.datecreated DESC
) i
INNER JOIN Users s
ON p.UserId = u.Id
WHERE (
@search IS NOT NULL
AND @search != ''
AND p.name = @search
)
OR (@search IS NULL)
OR (@search = '')
如何优化我的搜索查询以使其快速运行?在实践中,我的查询中有许多其他联接和更多活动,但是我认为这是问题所在,因为当我注释掉名字和姓氏搜索时,我的查询运行得非常快。
感谢所有帮助。
编辑:我也尝试过如下所示的内部连接和子查询,但是这产生的结果比最初显示的横向连接尝试更糟糕(执行时间约为 25 秒)
SELECT
p.id,
p.name,
c.firstname,
c.lastname
from Parents P
INNER JOIN children c
ON c.ParentId = p.Id
INNER JOIN Users s
ON p.UserId = s.Id
WHERE c.datecreated = (
select max(c1.datecreated) from children c1 where c1.ParentId = c.ParentId
)
and @search IS NOT NULL
AND @search != ''
AND (
@search = c.firstname
OR @search = c.lastname
OR p.name = @search
)
OR @search IS NULL
OR @search = ''
)
【问题讨论】:
第一个查询应该做什么?返回最近创建的 Children 记录具有匹配名称的父母(这是查询所做的)或返回至少有一个具有匹配名称的孩子的父母(这似乎是您想要的)。 返回的数据应该是所有父母的姓名和ID以及他们最近孩子的名字和姓氏。那么孩子的名字和姓氏应该是可搜索的。 @BaconBits 这更有意义吗? 使用“catch all”查询通常会生成一个相当糟糕的计划,因为优化器会在提供@search 时生成一个计划,但相同的计划在任何其他情况下都不起作用案例。常见的解决方案是使用动态 SQL 来完全避免多个 OR。我还建议先过滤名称,然后检查孩子是否是最新的。 @EzLo 您有任何示例或链接可以使这些建议更清晰吗?您将上述查询的哪一部分称为“全部”查询 推荐阅读:Dynamic Search Conditions in T-SQL. 【参考方案1】:仅基于您问题的这一部分,我相信您遇到了参数嗅探问题。
我的查询从 1 秒或更短时间运行到大约 16 秒运行
请在查询末尾添加OPTION (RECOMPILE)
,看看会发生什么(但请调查此问题的含义并了解 CPU 后果)。也可以看OPTIMIZE FOR UNKNOWN
盲从,你可以尝试一些想法
将 1 次查找减少到Children
,即 WHERE c.datecreated = (select max(c1.datecreated) from children c1 where c1.ParentId = c.ParentId)
通过减少 @Search
逻辑来清理它
SELECT p.id,
p.name,
c.firstname,
c.lastname
FROM Parents P
INNER JOIN
(
select c1.firstname,
c1.lastname,
c1.ParentId,
row_number() OVER (PARTITION BY c1.ParentId ORDER BY c1.datecreated DESC) as RN
from children c1
) as c
ON c.ParentId = p.Id
AND c.RN = 1 --/*Get the Latest First,Lastname based on datecreated*/
INNER JOIN Users s
ON p.UserId = s.Id
WHERE 1 = 1
AND (
c.firstname = @search
OR c.lastname = @search
OR p.name = @search
-- if @search is either NULL / '' it will return
OR NULLIF(@search, '') IS NULL
)
--OPTION (RECOMPILE) /*Uncomment this and see does it improve*/
另外请注意,您可能会遇到参数嗅探问题,即因为 @search
是一个查询参数,它看起来可能会有很大差异。
您可以尝试在查询末尾添加OPTION RECOMPILE
看看是否有影响
如果您还没有尝试过,也可以尝试一下。
更新表的统计信息 碎片整理/重建索引 查看实施 ola.hellengren 维护计划最后,为了获得更多帮助,您可以使用 https://www.brentozar.com/pastetheplan/ 粘贴查询计划
【讨论】:
OPTION (RECOMPILE)
成功了 - 查询在 1 秒内恢复运行
看看这个***.com/a/40437749/7351346,看看OPTION (RECOMPILE)
或OPTION(OPTIMIZE FOR UNKNOWN)
哪个更好以上是关于使用横向连接搜索非常慢的主要内容,如果未能解决你的问题,请参考以下文章
MS Access 中通过 ODBC 连接 MS SQL 表的查询非常慢