【问题标题】:Using 'where then Union' or Using 'Union then Where'使用“where then Union”或使用“Union then Where”
【发布时间】:2015-05-19 21:11:24
【问题描述】:

请记住这两种查询:

--query1
Select someFields
From someTables
Where someWhereClues
Union all
Select someFields
FROM some Tables
Where someWhereClues

--query2
Select * FROM (
    Select someFields 
    From someTables
    Union all 
    Select someFields
    FROM someTables
    ) DT
Where someMixedWhereClues

注意:
在两个查询中,最终结果字段相同

我认为是第一个。查询更快或性能更好!
但是经过一些研究后,我对此note感到困惑:

SQL Server(作为 RDBMS 的示例)首先读取整个数据,然后查找记录。 => 所以在这两个查询中,所有记录都会读取和查找。

请帮助我解决我的误解,以及 query1 和 query2 之间是否还有其他区别?


编辑:添加示例计划:

select t.Name, t.type from sys.tables t where t.type = 'U'
union all
select t.Name, t.type from sys.objects t where t.type = 'U'

select * from (
    select t.Name, t.type from sys.tables t
    union all
    select t.Name, t.type from sys.objects t
    ) dt
where dt.type = 'U'

执行计划是:

两者相同且50%

【问题讨论】:

  • 您可以通过对两个查询运行执行计划来检查发生了什么。
  • 如果您检查给定数据的执行计划和服务器统计信息(时间/IO),那么您可以看到哪个更好。在我的脑海中,第一个看起来更好,但是 sql server 优化器可能足够聪明,可以使两者相等。因此 - 查看它运行的内容是分析的方式。
  • 我也加了执行计划!!??
  • 这基本上总是归结为一些基本建议:在 SQL 中,你应该告诉系统你想要什么,而不是如何去做和对于大多数情况,如果有多种方法可以编写逻辑上等效的同一查询,则优化器应该为任何查询生成相同的计划。因此,只需编写您认为读得最好的查询,并且仅在 测量的 性能不满足您的要求时才考虑更改查询。
  • 您问题中的查询对似乎逻辑上相同。我不明白你关于“读写”的措辞。优化器试图做的一件事是尽可能地“推”谓词(条件)。如果它可以在扫描每个基本表时检查谓词(而不是需要检查涉及多个表的内容),那么它将在扫描表时执行这些检查(或在索引中查找)。

标签: sql-server performance union rdbms query-performance


【解决方案1】:

SQL Server query optimizer 优化了两个查询,因此您获得几乎相同的性能。

【讨论】:

    【解决方案2】:

    第一个不能慢。原因如下:

    • 如果第一个中的WHERE 子句可以有效地使用INDEX,那么UNION 中要收集的行将更少。更少的行 --> 更快。​​
    • 第二个在UNION 上没有INDEX,因此无法以这种方式优化WHERE

    以下是可能导致第一个变慢的事情。但我认为它们是例外,而不是规则。

    • 实现了不同的并行度。
    • 在您运行查询时碰巧缓存了不同的内容。

    警告:我假设所有三个 WHERE 子句都是相同的(如您的示例所示)。

    【讨论】:

    • Fewer rows --> faster 在我的印象中是这样的,但是看看[这篇关于 SQL Server 如何执行查询的文章](www.codeproject.com/Articles/630346/Understanding-how-SQL -Server-executes-a-query),我的问题笔记来自那里;)。
    • 长文章(很好)。它的哪个特定部分与这里相关?
    【解决方案3】:

    根据经验,我将始终考虑使用第一种查询类型。

    在带有简单WHERE 谓词的虚构样本和查询中,两者都将使用相同的计划。但是在更复杂的查询中,使用更复杂的谓词,优化器可能无法为第二种查询提供同样有效的解决方案(它只是一个优化器,并且受资源和时间限制)。查询越复杂,优化器找到最佳执行计划的机会就越小(因为它最终会超时并选择迄今为止发现的最差的计划)。如果谓词是 ORed,情况会变得更糟。

    【讨论】:

      【解决方案4】:

      SQLServer 会将这两个查询优化为同一事物,如您发布的执行计划所示。它能够做到这一点是因为在这种情况下查询相当简单;在另一种情况下,结果可能会有所不同。只要您正在编写查询,就应该尝试遵循与优化器相同的一般规则,并尽快过滤以限制返回的结果集。通过告诉它您首先只想获取“U”记录,然后然后组合这些结果,您将为以后的修订准备查询,这可能会使优化器的选择无效,从而导致相同的执行计划。

      简而言之,您不必强制简单查询为最佳,但这是一个好习惯,并且在创建更复杂的查询时会有所帮助。

      【讨论】:

        【解决方案5】:

        在我的实践中,第一个选项永远不会比第二个慢。我认为优化器足够聪明,可以或多或少地以相同的方式优化这些计划。但是我做了一些测试,第一个选项总是更好。例如:

        CREATE TABLE #a ( a INT, b INT );
        
        WITH Numbers ( I ) AS (
            SELECT 1000
        
            UNION ALL
        
            SELECT I + 1
            FROM Numbers
            WHERE I < 5000
        )
        INSERT INTO #a ( a )
        SELECT I
        FROM Numbers
        ORDER BY CRYPT_GEN_RANDOM(4)
        OPTION ( MAXRECURSION 0 );
        
        WITH Numbers ( I ) AS (
            SELECT 1000
        
            UNION ALL
        
            SELECT I + 1
            FROM Numbers
            WHERE I < 5000
        )
        INSERT INTO #a ( b )
        SELECT I
        FROM Numbers
        ORDER BY CRYPT_GEN_RANDOM(4)
        OPTION ( MAXRECURSION 0 );
        
        SELECT a, b
        FROM #a
        WHERE a IS NOT NULL
        UNION ALL
        SELECT a, b
        FROM #a
        WHERE b IS NOT NULL
        
        SELECT *
        FROM (
            SELECT a, b
            FROM #a
            UNION ALL
            SELECT a, b
            FROM #a
            ) c
        WHERE a IS NOT NULL
            OR b IS NOT NULL
        

        结果是 47% 对 53%

        【讨论】:

        • 我发现Union All 的结果比使用OR 将查询更改为WHERE a IS NOT NULL 线索更好,然后检查它们,如果你检查了你的结果,你可以看到你的第一个查询返回8002 行,第二个查询返回16004 行,所以它们不一样。
        【解决方案6】:

        根据我的经验,对此没有直接的答案,它会根据底层查询的性质而有所不同。正如您所展示的,优化器在这两种情况下都提出了相同的执行计划,但情况并非总是如此。性能通常相似,但有时性能可能会因查询而有很大差异。一般来说,我只会在无缘无故地表现不佳时仔细研究它。

        【讨论】:

          猜你喜欢
          • 2016-01-09
          • 1970-01-01
          • 1970-01-01
          • 2016-05-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-12-23
          相关资源
          最近更新 更多