【问题标题】:When does WHERE filtering occur? [duplicate]WHERE 过滤何时发生? [复制]
【发布时间】:2013-03-04 16:00:22
【问题描述】:

如果我有这样的查询:

SELECT
    A.ID,
    A.Name,
    A.Type,
    B.FirstName,
    B.LastName,
    B.DateOfBirth,
    C.OfficeName
FROM A
    INNER JOIN B ON A.ContactID = B.ID
    INNER JOIN C ON B.OfficeID = C.ID
WHERE
    A.Type = 1

什么时候应用 A.Type = 1 过滤器?是在连接之后,还是查询查找“A”,确定它是否通过过滤器,如果通过,则只连接到 B 和 C?

希望这是有道理的。谢谢。

【问题讨论】:

  • 能否包含查询执行计划?这可能会回答您的问题。
  • 我一直认为查询优化器会发现它并将其应用到最佳(或接近)的位置。在 SSMS 中打开“包括实际查询计划”选项运行查询,看看会发生什么。
  • 它有什么改变吗?当然,只要结果是正确的。 SQL Server 将使它变得更高效。
  • @mellamokbtheWise - 这只是我很好奇的事情。我只是想知道 SQL 是否遵循任何可靠的规则。通常情况下,答案似乎是“视情况而定”。 :)
  • 一本数据库系统教科书将涵盖这一点。通常,WHERE 条件应尽早处理,因为它们会减小要进一步处理的行集的大小。

标签: sql sql-server


【解决方案1】:

首先,以下是 SQL 操作顺序:

  • FROM 子句
  • WHERE 子句
  • GROUP BY 子句
  • HAVING 子句
  • SELECT 子句
  • ORDER BY 子句

在一个简单的查询中,过滤发生在FROM 子句之后(在这部分找到连接)。您上面的查询所做的是主要将表与定义它们关系的链接列连接起来。设置记录后(连接的结果),然后发生WHERE 子句以过滤掉等于1 的Type


这是另一个使用LEFT JOIN的例子,

第一个查询:

SELECT  A.ID,
        A.Name,
        A.Type,
        B.FirstName,
        B.LastName,
        B.DateOfBirth
FROM    A
        LEFT JOIN B 
            ON  A.ContactID = B.ID AND
                B.LastName = 'Michaels'

vs 第二个查询:

SELECT  A.ID,
        A.Name,
        A.Type,
        B.FirstName,
        B.LastName,
        B.DateOfBirth
FROM    A
        LEFT JOIN B ON  A.ContactID = B.ID
WHERE   B.LastName = 'Michaels'

第一个查询返回表A 中的所有记录。 B.LastName = 'Michaels' 所做的是在表B 与表A 连接之前,它过滤掉所有LastName 等于Michaels 的记录。因此,表 A 中的记录与表 B 上的过滤记录不匹配的记录将在表 B 的列上具有 NULL 值。

第二个查询不会产生与第一个查询相同的结果,并且执行与 INNER JOIN 完全相同的结果,因为在连接记录后,将对结果执行另一个过滤,并且只获取 LastName 的记录等于 Michaels

【讨论】:

    【解决方案2】:

    逻辑上 - 在joins 之后,物理上 - 取决于优化器。

    【讨论】:

      【解决方案3】:

      MSDN.
      检查标题为SELECT 语句的逻辑处理顺序

      的部分
      1. 来自
      2. 开启
      3. 加入
      4. 在哪里
      5. 分组
      6. 使用 CUBE 或使用 ROLLUP
      7. 选择
      8. 不同的
      9. 订购人
      10. 顶部

      在此列表之前的段落末尾有一个重要说明。

      请注意,语句的实际物理执行由查询处理器确定,顺序可能与此列表不同。

      【讨论】:

        【解决方案4】:

        要回答这个问题,您确实需要查看执行计划。在您提到的情况下,如果您在 where 子句中有一个可搜索的参数(SARG),则过滤器很可能会在连接之前与您的访问方法一起应用,即索引、表扫描等。

        使用

        查询菜单 -> 包括实际执行计划

        查询菜单 -> 显示估计的执行计划

        去看看。

        【讨论】:

          【解决方案5】:

          where 子句将在 join 之前应用,即它将返回 A 的所有行以及 B 和 C 中的相应行取决于连接条件和 type = 1

          【讨论】:

            猜你喜欢
            • 2017-11-27
            • 2017-03-13
            • 2019-05-01
            • 2019-03-24
            • 2018-02-13
            • 2016-10-09
            • 2019-10-21
            • 2011-10-28
            • 2012-12-25
            相关资源
            最近更新 更多