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()
希望这对您有所帮助
对我有用的是将查询的结果设置到一个变量中,然后比较变量,不要问我为什么,它只是唤醒了我。无法解释
(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 existsSELECT top 1 1 AS junk INTO #me 从你的疯狂查询这里 如果存在 ( SELECT 1 从我 ) SELECT GETDATE()
希望这对您有所帮助
对我有用的是将查询的结果设置到一个变量中,然后比较变量,不要问我为什么,它只是唤醒了我。无法解释