【问题标题】:Performance of inner join compared to cross join与交叉连接相比,内连接的性能
【发布时间】:2010-10-14 20:00:06
【问题描述】:

发出内部连接的效果与使用 WHERE 子句中的连接条件声明交叉连接的效果相同。我注意到我公司的很多人都使用交叉联接,而我会使用内部联接。在更改其中一些查询后,我没有注意到任何显着的性能提升,并且想知道这是否只是巧合,或者 DBMS 是否透明地优化了这些问题(在我们的例子中是 MySql)。这里有一个具体的例子供讨论:

SELECT User.*
FROM User, Address
WHERE User.addressId = Address.id;

SELECT User.*
FROM User
INNER JOIN Address ON (User.addressId = Address.id);

【问题讨论】:

  • 第一个不是 ANSI SQL。我知道 Microsoft 已建议使用第二个示例的语法。 MySQL 可能会做同样的事情,因为它们是公司的。此外,第一个不是交叉连接。如果您省略 where 子句,则将是交叉连接。
  • 您调用的交叉连接是一种较旧的语法。我们恐龙:) 倾向于使用它。内连接语法被认为是 SQL 92 (IIRC) 标准的一部分。从那时起,供应商已经开始支持它,大多数供应商都支持这两者。因此它不是 ANSI,因为它不在文档中。
  • @WakeUpScreaming +1 指出此处没有显示交叉连接。

标签: sql performance


【解决方案1】:

使用EXPLAIN 查看两个查询的查询计划,看看是否有任何不同。 MySQL 很可能在这两种情况下都使用相同的执行计划。我使用INNER JOIN 语法主要是因为它更清晰。

【讨论】:

    【解决方案2】:

    除了内部连接更清晰之外没有区别,因为它定义了连接,而将 where 子句作为实际的限制条件。

    【讨论】:

      【解决方案3】:

      交叉连接产生的结果由来自两个或多个表的行的每个组合组成。这意味着如果表 A 有 6 行,表 B 有 3 行,则交叉连接将产生 18 行。这两个表之间没有建立关系——实际上你只是产生了所有可能的组合。

      使用内部联接,表的一行中的列值与另一个(或同一个)表的另一行中的列值组合形成单行数据。

      如果将 WHERE 子句添加到交叉连接,则它的行为类似于内部连接,因为 WHERE 施加了限制因素。

      只要您的查询符合常识和供应商特定的性能指南 (i),我喜欢将决定使用哪种连接类型视为一个简单的品味问题。

      (i) 供应商特定绩效指南

      1. MySQL Performance Tuning and Optimization Resources
      2. PostgreSQL Performance Optimization

      【讨论】:

        【解决方案4】:

        加入表格或放置 ON / WHERE 条件的顺序无关紧要。

        查询优化器无论如何都应该优化和使用最佳顺序(并选择如何最好地过滤数据、从哪里开始等)

        与其他许多人一样,我建议使用 INNER JOIN 语法,因为它使内容更具可读性,它也更透明地使用 LEFT 或 FULL 连接的语法。

        这里有更多关于它的文字:http://linus.brimstedt.se/?/article/articleview/SQL Syntax

        /B

        【讨论】:

          【解决方案5】:

          第一个示例在功能上与第二个示例相同。但是,出于几个原因,应该避免使用这种语法。首先,使用此语法时更容易意外获得交叉连接,尤其是当表中有多个连接时。如果您看到很多带有关键字 distinct 的此类查询,则可能有人正在尝试修复交叉连接。

          接下来,使用旧样式的左右连接语法已被弃用,将不再受支持。此外,它现在无论如何都不能正常工作。有时它会误解外连接并返回错误的结果集。因此,您在 where 子句中使用 = 或 = 的任何查询都应立即被替换。

          第三,ANSI 标准连接更易于理解和维护。对连接的理解是查询任何关系数据库的任何人都需要具备的最关键的基本技能之一。根据我的经验,一些使用旧样式的人并不真正了解连接及其工作原理,因此编写的查询实际上并没有达到他们的预期。

          【讨论】:

            【解决方案6】:

            我发现允许第一种语法(逗号分隔表)的工作场所往往会花费大量时间来调试返回的行数多于预期的情况。无意的交叉连接是系统的祸根,甚至可以使最优化的数据库崩溃。去年,它至少两次让我们的预生产系统戛然而止。

            第二种语法(连接语法)迫使作者首先考虑如何将表连接在一起,然后只返回有趣的行。使用这种语法不可能意外地进行交叉连接,从而降低了意外执行不良查询的危险。

            但是,抛开这个问题不谈,我从未注意到在我拥有的任何系统中这两种语法之间的速度差异。

            【讨论】:

              【解决方案7】:

              第一种语法的另一个好处是您可以在限制条件下更加通用。不仅仅是平等。

              但是如果你使用相等,为什么要相信优化器呢?确保它不会首先生成交叉连接然后消除行。使用第二个。

              【讨论】:

              • 对 MySQL 来说可能是真的,我不知道。但是在sql server中,可以在“on”的右边加上除相等以外的其他条件。
              • 你可以在 MySQL 中做同样的事情。
              【解决方案8】:

              SQL Server 说“当 WHERE 将交叉连接变为内部连接时”, 所以没有区别。 http://msdn.microsoft.com/en-us/library/ms190690.aspx

              我做了SQL server“执行计划”,性能是一样的。

              【讨论】:

                【解决方案9】:

                从一开始,优化器就围绕经典的 restrict-project-cartesian 乘积语法构建。几乎所有的供应商都复制了 System R 开创的设计。然后,供应商不情愿地采用了“最新最好的”ANSI 语法并改进了他们的 SQL 执行引擎。与营销手册告诉您的(“使用最新语法”)相反,物理实现级别没有太大变化:它仍然是 [indexed] 嵌套循环,或者散列或排序合并连接。因此,假设一种语法优于另一种语法是没有根据的。

                根据我的个人喜好,新语法是redundant、嘈杂和inconsistent。至于被委员会批准,“走进每个城市的任何公园,你都找不到委员会的雕像”。

                【讨论】:

                • 使用隐式连接是一种 SQL 反模式。它会受到意外交叉连接的影响,特别是如果您需要在某些时候更改为外连接(您不应将两者混合,并且外连接隐式语法至少在某些数据库中无法正常工作),则更难维护。如果您确实想要交叉连接,则无法判断这是否正确,或者您是否遇到意外的交叉连接问题。所以意图不明确。这只是一种糟糕的做法。
                【解决方案10】:

                解释两个查询给出相同的输出

                mysql> explain select * from t T1, t T2 where T1.ID=T2.ID;
                +----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
                | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                          |
                +----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
                |  1 | SIMPLE      | T1    | ALL  | PRIMARY       | NULL | NULL    | NULL |    3 |                                |
                |  1 | SIMPLE      | T2    | ALL  | PRIMARY       | NULL | NULL    | NULL |    3 | Using where; Using join buffer |
                +----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
                2 rows in set (0.00 sec)
                
                mysql> explain select * from t T1  join t T2 on T1.ID=T2.ID;
                +----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
                | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                          |
                +----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
                |  1 | SIMPLE      | T1    | ALL  | PRIMARY       | NULL | NULL    | NULL |    3 |                                |
                |  1 | SIMPLE      | T2    | ALL  | PRIMARY       | NULL | NULL    | NULL |    3 | Using where; Using join buffer |
                +----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
                2 rows in set (0.00 sec)
                

                但最好使用内连接语法,因为它更清晰、更精确。 与交叉连接相比,Mysql 可能会在内部调整左右连接查询以选择更少的数据。

                【讨论】:

                  【解决方案11】:

                  使用 where 子句的交叉联接和内部联接之间没有太大区别,它们可能是相同的,但是使用内部联接我们会减少代码中的某些部分。

                  【讨论】:

                    猜你喜欢
                    • 2011-07-20
                    • 2010-09-09
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-03-14
                    • 1970-01-01
                    • 2014-03-26
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多