查询与查询 - 为什么这个比另一个更快?

时间:2011-04-07 14:25:00

标签: sql sql-server sql-server-2005 query-optimization sql-optimization

我有以下两个问题 - 原始是第一个,第二个是我的轻微“升级”。第一个运行需要将近一秒钟,第二个运行完毕才能完全脱离刷新按钮。

我的问题:为什么?

第一个和第二个之间的唯一区别是第一个使用coalesce来获取比较berp.ID_PART_SESSION的值,第二个使用union来将两个select语句放在一起来完成同样的事情。

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

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)

VS

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)

3 个答案:

答案 0 :(得分:2)

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

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

此外,我强烈推荐使用Instant SQL Formatter(与StackOverflow编辑器中的{}图标相结合)等工具,使您的问题中的查询更易于阅读:

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)

VS

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 :(得分:0)

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

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

答案 2 :(得分:0)

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