【问题标题】:INNER JOIN vs CROSS JOIN vs CROSS APPLYINNER JOIN vs CROSS JOIN vs CROSS APPLY
【发布时间】:2017-03-03 19:37:35
【问题描述】:

SQL 的乐趣之一是通常有多种方法可以做同样的事情,那么哪种方法是“最好的”?

在这种情况下,我从“导入”表中插入记录,并为它们提供默认的“查看器”安全级别(在不同的数据库中可能有不同的密钥 ID)。我可以通过至少三种不同的方式(甚至可能更多)做到这一点:CROSS JOIN、CROSS APPLY 和 INNER JOIN。关于哪个最适合性能或设计目的的任何建议?我倾向于交叉申请。

这个问题可能已经有答案了,但是找不到,最近在开发中不断遇到这个需求,不妨学习一下最好的方法。

以下是 3 个示例语句。加入 SecRole 表的最佳方法是什么?

INSERT INTO LocStaff (LocationID, StaffID, SecRoleID)
    SELECT i.LocationID, s.StaffID, sr.SecRoleID
    FROM IntStaff i
        JOIN Staff s ON i.EmployeeID = s.StaffNumber
        CROSS JOIN SecRole sr
    WHERE sr.Name = 'Viewer' 

INSERT INTO LocStaff (LocationID, StaffID, SecRoleID)
    SELECT i.LocationID, s.StaffID, sr.SecRoleID
    FROM IntStaff i
        JOIN Staff s ON i.EmployeeID = s.StaffNumber
        JOIN SecRole sr ON sr.Name = 'Viewer'

INSERT INTO LocStaff (LocationID, StaffID, SecRoleID)
    SELECT i.LocationID, s.StaffID, sr.SecRoleID
    FROM IntStaff i
        JOIN Staff s ON i.EmployeeID = s.StaffNumber
        CROSS APPLY (SELECT TOP 1 SecRoleID FROM SecRole WHERE Name = 'Viewer') sr

【问题讨论】:

  • 我不认为cross join 在大多数情况下可以与其他两个相媲美。那么你的问题就变成了inner join vs cross apply,这里是:stackoverflow.com/questions/1139160/…
  • 不太重复,因为另一个主要关注何时使用交叉应用,但如果你的断言是正确的,交叉连接应该被彻底拒绝,我认为另一篇文章建议交叉应用应该比 INNER JOIN 快。当只拉一张唱片时会是这种情况,还是真的没有区别,而这更像是个人喜好?
  • 您的示例查询在尝试比较这些不同操作的上下文中没有意义。您本质上是通过三种不同的方式将一个常量值添加到您的查询中。您也可以只使用局部变量或在您的选择中使用子查询。 SecRoleID 与您查询的其余部分没有关系
  • 你是对的。我正在尝试将适当的 SecRoleID 添加到插入的每条记录中。它可以是一个局部变量(使用 SELECT 来设置它 WHERE Name = 'Viewer'),或者是一个子查询。您觉得其中任何一个解决方案都比使用 Cross Apply 更好吗?

标签: sql sql-server join


【解决方案1】:

前两个是等价的。在这种情况下,您是使用内部联接还是交叉联接实际上是一个偏好问题。我想我通常会使用cross join,因为没有真正的连接条件在表之间

注意:当意图是在表之间具有匹配条件的“真实”inner join 时,您应该切勿使用cross join

cross apply 没有做同样的事情。它只选择一排。如果您的意图是最多获得一个匹配行,请使用cross apply。如果目的是得到一个匹配的行,那么使用outer apply

【讨论】:

  • 我不知道 OUTER APPLY;听起来像是第四种方法。您不会知道这一点(因为我没有说明),但是由于目标表中的 SecRoleID 不是 NULL,我确实在寻找一个匹配的行。你是说 CROSS APPLY (TOP 1) 可能返回 NULL,所以它不是一个合适的解决方案?
  • @ScottDuncan。 . .没有。CROSS APPLY (TOP 1) 做你想做的事。其他人似乎不会。如果表之间不匹配,OUTER APPLY 将返回 NULL 值。
  • 你提到前两个是等价的。这是真的,还是交叉连接在过滤之前连接所有行,而内连接只连接一个所需的行?无论哪种方式,我都倾向于交叉申请,因为它似乎最清楚地表明了意图。我担心性能,但上面提供的 SqlZim 链接似乎表明 Cross Apply 应该有更好的性能。
  • @ScottDuncan。 . . SQL 语句描述结果集。优化选择最佳执行计划。我熟悉的每个优化器都会将两者视为相同。
  • FWIW 我只是想在这里写一个注释,因为有人提出优化器似乎并不总是在 INNER JOIN 和 CROSS JOIN 之间选择最佳执行计划,即使数据集相同也是如此。就我而言,我在两个表中有一列对于所有行都是相同的常量值。因此,该列上的 CROSS JOIN 和 INNER JOIN 是相同的。但是,如果该列在以后的连接中使用,优化器似乎没有保留它已修复的知识,因此做了很多不必要的比较,而使用 INNER JOIN 它“记住”它们匹配。
【解决方案2】:

只有当我们在表之间没有任何共同的列(不是最好的结构设计!)或者我们需要所有可能的情况时,我们才使用交叉连接(或仅使用关键字 Join)。我不知道您的表结构,但我假设表 SecRole 对 Staff 和 InsStaff 没有外键或公用键。在这种情况下,我将在此处使用右连接(外连接)从 Staff 和 InsStaff 之间的第一个内连接中获取所有结果,然后将它们放在 SecRole 所需记录的旁边。

这里是右连接的概念 http://www.dofactory.com/sql/right-outer-join

【讨论】:

  • 问题是,当 SecRole 和其他表之间没有公用键时,最好的方法是从 SecRole 中附加一个值,那么“把它们放在旁边”是什么意思(正好一个) 来自 SecRole 的所需记录?我的示例显示了三种可能的方法,我想知道哪种方法最好,还是有第四种更好的方法?您是否建议在 SecRole 上加入 Right Outer Join?既然没有公用键,那么 ON 子句是什么,它比带有 WHERE 过滤器的 CROSS JOIN 或带有 ON 子句中的过滤器的 LEFT JOIN 更好吗?
  • 对不起,我的意思是 INNER JOIN,而不是 LEFT JOIN(显然你只有 5 分钟的时间来发现一个错字并就地修复它)。
猜你喜欢
  • 2019-02-18
  • 2014-06-23
  • 2013-07-19
  • 1970-01-01
  • 1970-01-01
  • 2021-09-20
  • 1970-01-01
  • 2014-11-17
  • 2022-01-01
相关资源
最近更新 更多