查询与查询 - 为啥这个比另一个快?

Posted

技术标签:

【中文标题】查询与查询 - 为啥这个比另一个快?【英文标题】:Query vs query - why is this one quicker than the other?查询与查询 - 为什么这个比另一个快? 【发布时间】:2011-04-07 14:24:59 【问题描述】:

我有以下两个疑问 - 原来是第一个,第二个是我的轻微“升级”。第一个需要将近一秒钟的时间来运行,第二个完成后我的手指才能完全离开刷新按钮。

我的问题:为什么?

第一个和第二个之间的唯一区别是第一个使用合并来获取一个值来比较berp.ID_PART_SESSION,第二个使用联合将两个选择语句放在一起以完成相同的事情。

我仍然认为第一个应该更快(我使用合并的最初原因),因为它似乎应该做更少的工作来获得相同的结果。考虑到我破译执行计划的能力有多弱,有人能解释一下为什么第二个查询比第一个好得多吗?

declare @animator varchar
SELECT TOP 1 @animator = FULL_NAME
FROM T_BERP berp
INNER JOIN dbo.T_INTERV i ON i.ID_INTERV = berp.ID_INTERV
WHERE berp.VERSION = 1
    AND berp.PRINCIPAL = 1
    AND berp.DELETED = 0
    AND berp.CANCELLED = 0
    AND berp.ID_PART_SESSION = (
        select coalesce(pss.ID_PART_SESSION, psst.ID_PART_SESSION)
        from t_bersp b
        LEFT JOIN T_PART_SESSION pss ON b.ID_PART_SESSION = pss.ID_PART_SESSION
        LEFT JOIN T_PSS_TEMP psst ON b.ID_PSS_TEMP = psst.ID_PSS_TEMP
        where ID_BERSP = 4040)

declare @animator varchar
SELECT TOP 1 @animator = FULL_NAME
FROM dbo.T_BERP berp
INNER JOIN dbo.T_INTERV i ON i.ID_INTERV = berp.ID_INTERV
WHERE berp.VERSION = 1
    AND berp.PRINCIPAL = 1
    AND berp.DELETED = 0
    AND berp.CANCELLED = 0
    AND berp.ID_PART_SESSION IN (
        select pss.ID_PART_SESSION
        from dbo.t_bersp b
        LEFT JOIN dbo.T_PART_SESSION pss ON b.ID_PART_SESSION = pss.ID_PART_SESSION
        where ID_BERSP = 4040
        union
        select psst.ID_PART_SESSION
        from dbo.t_bersp b
        LEFT JOIN dbo.T_PSS_TEMP psst ON b.ID_PSS_TEMP = psst.ID_PSS_TEMP
        where ID_BERSP = 4040)

【问题讨论】:

每当我需要比较两个查询时,通常是很简单的第一步到see what the execution plan looks like。一旦你有了这个计划,我就会把它添加到你的问题中。 我最初的想法是子查询顶部的= 和底部的IN,但它不相关,所以我认为这不重要...... 您还有一个区别,即第一个查询使用“=”,第二个查询使用“IN”。同样作为一个不相关的警告,使用没有 ORDER BY 的 TOP 1 可能会导致一些非常难以追踪的错误。如果您没有 order by,则返回多条记录的顺序是不确定的。它通常会匹配索引的排序顺序或磁盘上的物理顺序,但不能保证。 @RozWel - 这里有关于=IN 的回声吗? :) 我有执行计划,但它们很大(~450 和~375 行)xml 文件。直接放在那里可以吗?好像找不到文件附件功能... 【参考方案1】:

如果不了解查询中各个表的相对大小和索引,就很难提供明确的答案。一种可能性:如果 t_part_session 和 t_pss_temp 都很大,则查询优化器可能会对您的第一个查询的内部 SELECT 中的两个 LEFT JOIN 做一些低效的事情。

编辑澄清:是的,两个查询中都有 LEFT JOIN,但我的猜测是,将两个查询放在一起(查询 1)可能会对 UNION(查询 2)的性能产生不利影响。抱歉,如果最初不清楚。

此外,我强烈推荐使用诸如 Instant SQL Formatter(与 *** 编辑器中的 图标结合)之类的工具,以使您的问题中的查询更易于阅读:

DECLARE @animator VARCHAR

SELECT TOP 1 @animator = full_name
FROM   t_berp berp
       INNER JOIN dbo.t_interv i
         ON i.id_interv = berp.id_interv
WHERE  berp.version = 1
       AND berp.principal = 1
       AND berp.deleted = 0
       AND berp.cancelled = 0
       AND berp.id_part_session = (SELECT
           Coalesce(pss.id_part_session, psst.id_part_session)
                                   FROM   t_bersp b
                                          LEFT JOIN t_part_session pss
                                            ON b.id_part_session =
                                               pss.id_part_session
                                          LEFT JOIN t_pss_temp psst
                                            ON b.id_pss_temporaire =
                                               psst.id_pss_temporaire
                                   WHERE  id_bersp = 4040)

DECLARE @animator VARCHAR

SELECT TOP 1 @animator = full_name
FROM   dbo.t_berp berp
       INNER JOIN dbo.t_interv i
         ON i.id_interv = berp.id_interv
WHERE  berp.version = 1
       AND berp.principal = 1
       AND berp.deleted = 0
       AND berp.cancelled = 0
       AND berp.id_part_session IN (SELECT pss.id_part_session
                                    FROM   dbo.t_bersp b
                                           LEFT JOIN dbo.t_part_session pss
                                             ON b.id_part_session =
                                                pss.id_part_session
                                    WHERE  id_bersp = 4040
                                    UNION
                                    SELECT psst.id_part_session
                                    FROM   dbo.t_bersp b
                                           LEFT JOIN dbo.t_pss_temp psst
                                             ON b.id_pss_temporaire =
                                                psst.id_pss_temporaire
                                    WHERE  id_bersp = 4040)  

【讨论】:

-1 - LEFT JOINs 也在第二个查询中,所以你的“答案”基本上相当于“我不知道,但请更好地格式化你的代码” 是的,左连接在两个查询中,但我猜测将两个连接在一起可能会对性能产生不利影响。抱歉,如果不清楚。对于它的价值,我同意 Chris 的评论,即执行计划将大大有助于解决这个问题。 抱歉,我曾尝试格式化代码,但我看到它是用反引号来做的,所以我把我的代码用反引号包裹起来,假设这已经足够了。 不用担心,如果我的回答显得傲慢,我很抱歉——显然我没有足够的声誉来直接编辑。只是想帮忙。不确定我是否有资格评论是否可以粘贴执行计划。 :-) 另外,当我从 SQL Formatter 粘贴格式化代码时,预览会损坏它,直到我使用 ,这看起来就像它只是在文本编辑器中缩进了它。 非常感谢。巧合的是,这次谈话现在给了我足够的声誉,我可以对帖子发表评论,而不是通过答案要求澄清。我以前没有那个。 :-)【参考方案2】:

我打赌这是合并声明。我相信 coalesce 最终会在 where 子句之前应用。所以,它实际上是遍历两个表的每个组合,然后过滤那些与 where 子句匹配的表。

【讨论】:

对于 SQL Server 来说,这将是一种非常愚蠢的处理方式......您可能是对的,它可以解释其中的奥秘,但让我感到惊讶的是,可以完成这样一个次优的事情。跨度> 【参考方案3】:

您可以将两个查询放在 SSMS 中的同一个批次中并显示执行计划 - 这不仅可以让您并排查看它们,还可以显示相对成本。

我怀疑 IN (UNION) 意味着第二个可以很容易地并行化。

【讨论】:

嗯,这更令人困惑 - 它告诉我第一个(也是最慢的)查询的成本(相对于批次)为 27%,第二个查询的成本为 73%。 @Alex In Paris 是实际的还是估计的?第二个使用并行性吗?读取的实际统计数据是什么样的? 我选择了“包括实际执行计划”。我没有看到任何地方提到并行。第一个查询有一个带有思考箭头的项目 - 聚集索引扫描,占该查询成本的 42%。 35% 用于聚集索引搜索。第二个查询有一个很大的项目成本:74% 用于 Key Lookup。不确定是否有任何帮助...

以上是关于查询与查询 - 为啥这个比另一个快?的主要内容,如果未能解决你的问题,请参考以下文章

mySql为啥查询时有时快,有时慢

sql语句联合查询 与 视图想比较的话,那个效率快,为啥。

在 latin1 中查询快,在 utf8 中查询慢 - 为啥?

为啥这个查询运行这么慢?

python 字典为啥这么快

请问在大数据量查询的时候,sql为啥比excel要快很多呢?谢谢!