【问题标题】:MySQL JOIN Abuse? How bad can it get?MySQL JOIN 滥用?能坏到什么地步?
【发布时间】:2009-12-05 10:57:31
【问题描述】:

我已经阅读了很多关于在每个 SELECT 上使用许多 JOIN 语句的关系数据库。但是,我一直想知道滥用此方法从长远来看是否存在任何性能问题。

例如,假设我们有一个users 表。我通常会添加“最常用”的数据,而不是做任何额外的 JOIN。例如,当我说“最常用”的数据是用户名、显示图片和位置时。

在网站上显示任何用户交互时始终需要此数据,例如:在每个 comments 表上加入 articles。无需在 usersusers_profiles 表上执行 JOIN 以获得“位置”和“显示”,只需使用 users 表上的信息即可。

这是我的方法,但是我知道有很多优秀且经验丰富的程序员可以就这件事给我一些建议。

我的问题是:

我应该尝试对 JOIN 保持保守吗?还是我应该更多地使用它们?为什么?

长期使用 JOIN 是否存在性能问题?

注意:我必须澄清一下,我根本不想避免 JOINS。我只在需要时使用它们。在此示例中,将是评论/文章作者、仅显示在用户个人资料页面上的额外个人资料信息......等等。

【问题讨论】:

  • 我希望 Cletus 能够回答这个问题。他的答案非常出色且发展良好。希望有人能用 4 行以上的方式回答。

标签: mysql database database-design


【解决方案1】:

我对数据建模的建议是:

  • 您应该更喜欢可选(可为空)列而不是 1:1 连接一般而言。仍然存在 1:1 有意义的情况,通常围绕子类型进行。与奇怪的连接相比,人们对可空列的态度往往更加娇气;
  • 除非真的合理,否则不要让模型过于间接(更多内容见下文);
  • Favour 加入而不是聚合。这可能会有所不同,因此需要对其进行测试。有关此示例,请参阅 Oracle vs MySQL vs SQL Server: Aggregation vs Joins
  • 连接优于 N+1 选择。例如,N+1 选择是从数据库表中选择一个订单,然后发出单独的查询以获取该订单的所有订单项;
  • 连接的可伸缩性通常只有在您进行批量选择时才会出现。如果您选择单行,然后将其加入一些事情,这很少是问题(但有时是);
  • 始终为外键编制索引,除非您正在处理一个很小的表;

更多内容请关注Database Development Mistakes Made by AppDevelopers

现在关于模型的直接性,让我举个例子。假设您正在设计一个用于用户身份验证和授权的系统。过度设计的解决方案可能如下所示:

  • 别名(id、用户名、user_id);
  • 用户(id,...);
  • 电子邮件(id、user_id、电子邮件地址);
  • 登录(id、user_id、...)
  • 登录角色(id、login_id、role_id);
  • 角色(ID、姓名);
  • 角色特权(id、role_id、privilege_id);
  • 权限(ID、姓名)。

因此,您需要 6 次连接才能从输入的用户名获得实际权限。当然,这可能有实际需求,但由于一些开发人员认为他们有朝一日可能需要它,即使每个用户只有一个别名,登录用户是 1 :1 等等。一个更简单的解决方案是:

  • 用户(ID、用户名、电子邮件地址、用户类型)

嗯,就是这样。也许如果您需要一个复杂的角色系统,但您也很可能不需要,并且如果您这样做的话,插入(用户类型成为用户类型或角色表中的外键)相当容易,或者映射通常很简单从旧到新。

这与复杂性有关:添加容易,删除难。通常情况下,它是对意外复杂性的持续警惕,如果不去增加不必要的复杂性并使其变得更糟,这就已经够糟糕了。

【讨论】:

  • 对复杂性的好评:“添加容易,删除难”
  • 非常感谢您的出色回答。它回答了我对此事的所有疑问。谢谢。
【解决方案2】:

某位聪明人曾经说过:

规范化,直到它受伤,反规范化,直到它工作!

这完全取决于连接的类型和连接条件,但它们并没有错。加入 ON table1.PK = table2.FK 非常有效。

【讨论】:

    【解决方案3】:

    如果数据是1 1,并且你不会有很多空字段,不要过度规范化。您仍然可以在 select 语句中指定所需的字段(“最常用的数据”)。

    【讨论】:

      【解决方案4】:

      害怕不加入。关系模型很强大,您应该使用它。有人总是讨论 N+1,但也考虑 - 在您的上下文中 - 经常出于安全目的加入反对用户,因为查询可以额外要求用户存在、状态、会话正确性和字段期望。

      许多大型网站甚至对每个请求都有会话表 http 请求表,它们总是相互连接以进行页面查询。好处是参数始终与会话匹配,会话与适当的用户匹配,用户状态始终检查,&c &c 但更多的是它允许一些有趣的横向扩展好处。

      说来话长,明智地去做,但不要吝啬加入。

      【讨论】:

        【解决方案5】:

        正如其他人所说 - 连接根本不是要避免的事情。事实上,在大多数模型中,应用程序运行的每个查询都很少有几个连接。

        即使在最大的查询中,它们通常也不是性能问题 - 并且通常可以解决如果您到处都有冗余和重复数据时会出现的性能问题。

        但是,请注意,在后台,数据库一次只连接两个表。因此,连接需要数据库执行多个对开发人员不可见的步骤。当它进行这些连接时,它必须做出一些关于如何进行的决定:

        • 遍历左侧表中的所有值,然后将它们一次匹配到右侧的值?
        • 反其道而行之?
        • 对两个表中的键进行排序并同时遍历它们?
        • 在两边建立密钥的散列?
        • 在给定联接之前或之后应用过滤条件?

        因此,如果您的联接最终很复杂,那么效率最终将取决于您的优化器/规划器的复杂程度以及统计信息的时效性和详细信息。 MySQL 在这里并不是一个强有力的竞争者——所以我通常会让我的模型和 sql 比我使用其他东西更简单一些。但是每个查询有几个连接应该几乎总是没问题的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-10-28
          • 1970-01-01
          • 2013-03-08
          • 2021-11-12
          • 2014-03-14
          • 1970-01-01
          • 2010-09-18
          • 1970-01-01
          相关资源
          最近更新 更多