SQL 服务器:IF EXISTS 大大减慢了查询速度

SQL Server: IF EXISTS massively slowing down a query

(SQL 正在使用 Server 2012)

我找到了一些关于查询优化的主题,并将 EXISTS 与 COUNT 进行比较,但我找不到这个确切的问题。

我有一个看起来像这样的查询:

select * from
tblAccount as acc
join tblUser as user on acc.AccountId = user.AccountId
join tblAddress as addr on acc.AccountId = addr.AccountId
... **a few more joins**
where acc.AccountId in (
    select * accountid from
    (select accountid, count(*) from tblUser
    where flag = 1
    group by accountId) as tbl where c != 1

这个查询立即运行(虽然数据库很大,大约 70Gb)。

当我将查询包装在 EXISTS 中时:

if exists
(
  **Exact same query as above**
)
begin
RAISERROR('Account found without exactly one flagged user.', 16, 1);
end
else
begin
  print 'test passed.'
end

查询突然需要大约 5-6 秒才能完成。我已经尝试指定 IF EXISTS (SELECT TOP 1 FROM... 并且还尝试了 NOT EXISTS(这甚至更慢)。但都无法加快速度。

如果正常的 select 查询基本上立即完成,那么有人知道为什么将它包装在 EXISTS 中会导致如此多的额外计算吗? And/or 任何人都有解决此问题的想法(我只是想在原始查询找到任何记录时抛出错误)。

谢谢!

尝试:

if exists
(
  select 1 from... etc
)

您是否尝试 运行 使用 TOP 1 的原始查询?很可能它会一样慢。

有时,当优化器认为某些事情很可能发生并且不费吹灰之力就 return 大量数据(即几乎所有记录都将得到 returned)时,它会选择主要是循环连接,因为它只需要获取第一个,而循环连接只适用于获取几条记录。当事实证明并非如此时,需要很长时间才能得到结果。

你的情况听起来很罕见,所以这个选择很伤人。尝试做类似 SELECT @count = COUNT(*) FROM ... 的事情,然后检查该计数是否非零。

尝试 SELECT 1 而不是 top 1 *。您实际上不需要 return 数据,您只是检查记录是否存在。

如果是存储过程,您也可以尝试清除查询缓存,如下所示:

获取计划句柄:

SELECT qs.plan_handle
FROM sys.procedures AS p WITH (NOLOCK)
INNER JOIN sys.dm_exec_procedure_stats AS qs WITH (NOLOCK)
ON p.[object_id] = qs.[object_id]
WHERE qs.database_id = DB_ID()
and p.name like '%SprocName%'
ORDER BY qs.execution_count DESC OPTION (RECOMPILE);

然后通过将句柄放入此调用来清除缓存:

DBCC FREEPROCCACHE (0x05000F00C616D37C40E15E64010000000000000000000000);

你有,什么,三个嵌套子查询?子查询总是很慢。您可以将其中至少一个转换为连接吗?如:

select acc.AccountId from tblAccount as acc
    join tblUser as user on acc.AccountId = user.AccountId
    join tblAddress as addr on acc.AccountId = addr.AccountId
    join (select accountid, count(*) as c from tblUser
          where flag = 1
          group by accountId) as tbl ON tbl.accountid = user.accountid
    where tbl.c != 1

我也遇到过这个问题。

当我单独 运行 查询时,查询是 10 毫秒,但是一旦我将其放入 If Exists 中,它就变成了 4 分钟。无论我尝试什么,它都不会回到 10 毫秒。该问题在 4 台不同的服务器上重现,但没有在 2 台服务器上重现。服务器都具有相同的数据库备份和相同的 mssql 2012 补丁级别。服务器在不同的 OS 和不同的硬件设置上。

我试过了

  • 调整最大内存 g运行t - 无影响
  • 更改并行度阈值 - 无影响
  • 重写查询以使其更简单 - 不影响
  • 使用前 1 - 没有影响
  • 清除了更改之间的缓存 - 不影响
  • 在我可以的地方将查询分解为一些索引视图(不能使用外部连接对部分进行分解)- 没有影响
  • 应用了推荐的缺失索引 - 将时间从 4 分钟减少到 3 分钟,但仍未达到我预期的 10 毫秒。
  • 将外连接更改为 where not in(子查询)- 不影响
  • 运行 sp_updateStats - 无影响

唯一对我有用的解决方案是将结果放在一个临时文件 table 中,然后根据该临时文件 table.

执行 if exists

SELECT top 1 1 AS junk INTO #me 从你的疯狂查询这里 如果存在 ( SELECT 1 从我 ) SELECT GETDATE()

希望这对您有所帮助

对我有用的是将查询的结果设置到一个变量中,然后比较变量,不要问我为什么,它只是唤醒了我。无法解释