查询在条件 IF 中变慢
Posted
技术标签:
【中文标题】查询在条件 IF 中变慢【英文标题】:Query slows down in Conditional IF 【发布时间】:2014-11-25 00:14:04 【问题描述】:我注意到在 SQL Server (2008 R2) 中运行以下代码需要 32 秒
IF ((SELECT COUNT(*) FROM view1) != 0)
OR ((SELECT COUNT(*) FROM view2) != 0)
OR ((SELECT COUNT(*) FROM view3) != 0)
OR ((SELECT COUNT(*) FROM view4) != 0)
OR ((SELECT COUNT(*) FROM view5) != 0)
OR ((SELECT COUNT(*) FROM view6) != 0)
PRINT 'HI'
然而,以下只用了 4 秒
SELECT
(SELECT COUNT(*) FROM view1)
, (SELECT COUNT(*) FROM view2)
, (SELECT COUNT(*) FROM view3)
, (SELECT COUNT(*) FROM view4)
, (SELECT COUNT(*) FROM view5)
, (SELECT COUNT(*) FROM viwe6)
我已经设法通过执行 SELECT COUNT(1)... + SELECT... != 0 来优化条件,这需要 4 秒,但查看执行计划并没有产生任何特别值得注意的结果。也没有太多机会用谷歌搜索这个词。
有人可以分享一下 SQL Server 优化器可能在背后做什么吗?
编辑:IF EXISTS 尝试耗时 38 秒。
IF EXISTS ((SELECT 1 FROM view1)
UNION (SELECT 1 FROM view2)
UNION (SELECT 1 FROM view3)
UNION (SELECT 1 FROM view4)
UNION (SELECT 1 FROM view5)
UNION (SELECT 1 FROM view6))
PRINT 'HI'
EDIT2:当前的 5 秒方法。
IF (SELECT COUNT(1) FROM view1)
+ (SELECT COUNT(1) FROM view2)
+ (SELECT COUNT(1) FROM view3)
+ (SELECT COUNT(1) FROM view4)
+ (SELECT COUNT(1) FROM view5)
+ (SELECT COUNT(1) FROM viwe6) != 0
PRINT 'HI'
EDIT3:在比较了 20 页大小的查询计划之后 - 似乎加速主要是由于底层视图在它们的连接之前进行部分聚合,而不是先连接然后聚合。
【问题讨论】:
执行 EXISTS( SELECT 1 FROM view1 ) 可以获得更好的性能,因为它会在找到一行后停止查看,而不是计算所有行。 我确实尝试过 EXISTS。但这也花了大约 38 秒。我会将我尝试过的内容放入编辑中。 快速思考将计数结果放入变量然后使用 IF 条件 嵌套视图可能会导致查询优化器出现问题,尤其是当它们深入时。经验法则是遵循百分比并单独攻击大百分比。 【参考方案1】:使用 TOP 1 语句:
例如:
DECLARE @CONTROL INT;
WITH CTE AS (
SELECT TOP 1 col FROM view1
UNION ALL
SELECT TOP 1 col FROM view2
UNION ALL
SELECT TOP 1 col FROM view3
UNION ALL
SELECT TOP 1 col FROM view4
UNION ALL
SELECT TOP 1 col FROM view5
UNION ALL
SELECT TOP 1 col FROM view6)
SELECT @CONTROL = COUNT(col) FROM CTE
IF @CONTROL != 0
PRINT 'HI'
【讨论】:
【参考方案2】:运行下面的代码需要多长时间?如果您将查询转换为EXISTS
,您将希望避免使用UNION,因为在您的示例中,您强制SQL 将每个视图中的每一行的SQL 转换为UNION
,然后查看元素是否存在。下面的答案将是机会主义尽快停止。
IF EXISTS(SELECT 1 FROM view1)
OR EXISTS(SELECT 1 FROM view2)
OR EXISTS(SELECT 1 FROM view3)
OR EXISTS(SELECT 1 FROM view4)
OR EXISTS(SELECT 1 FROM view5)
OR EXISTS(SELECT 1 FROM view6)
PRINT 'HI'
这是 TOP 与单个存在的替代方法 - 也许基于提供的解释,为什么多个 EXISTS 执行如此缓慢,对您来说应该更好。
IF EXISTS (
SELECT TOP (1) 1 FROM view1
UNION ALL SELECT TOP (1) 1 FROM view2
UNION ALL SELECT TOP (1) 1 FROM view3
UNION ALL SELECT TOP (1) 1 FROM view4
UNION ALL SELECT TOP (1) 1 FROM view5
UNION ALL SELECT TOP (1) 1 FROM view6
)
PRINT 'Hi'
至于您在后台的问题,下面的网址有一个很好的写法: http://sqlserverplanet.com/tsql/comparing-exists-vs-left-join-where-not-null
基本上,它描述了使用EXISTS
时未创建工作表,因此使用带有多个EXISTS
的单个语句,性能可能会像您的情况一样变慢。
【讨论】:
运气不好,这花了 29 秒。我推测问题不是尽快“退出” - 而是由于 if 语句,底层 SQL 优化引擎执行计划不佳。我仍在质疑它为什么以及它可能在幕后做什么。 您可以运行备用查询吗?我添加了一些信息和博客文章的链接,说明为什么像这样的多个 EXISTS 在某些情况下会变慢。 有趣的是上述两个查询的执行计划是相同的,但据说单个 EXISTS 应该更优化 备用查询是 28 秒 - 所以它单存在确实更优化以上是关于查询在条件 IF 中变慢的主要内容,如果未能解决你的问题,请参考以下文章