MySQL加入滥用?它有多糟糕?

时间:2009-12-05 10:57:32

标签: mysql database database-design

我在每个SELECT上使用许多JOIN语句阅读了很多关于关系数据库的内容。但是,我一直想知道在滥用这种方法时长期存在任何性能问题。

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

在网站上显示任何用户互动时,始终需要此数据,例如:在comments的每个articles表JOIN上。而不是在users&上进行加入。获取“位置”和“显示”的users_profiles表,只需使用users表中的信息。

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

我的问题是:

我应该尝试对JOIN保守吗?或者我应该更多地使用它们?为什么呢?

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

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

5 个答案:

答案 0 :(得分:8)

我对数据建模的建议是:

  • 你应该支持1:1加入一般来说的可选(可空)列。仍然存在1:1有意义的情况,通常围绕子类型。对于可空栏目,人们往往比他们奇怪的加入时更加娇气;
  • 除非确实合理,否则不要将模型设为间接;(详见下文);
  • 支持加入聚合。这可能会有所不同,因此需要进行测试。有关此示例,请参阅Oracle vs MySQL vs SQL Server: Aggregation vs Joins;
  • 联接优于N + 1选择。例如,N + 1选择是从数据库表中选择订单,然后发出单独的查询以获取该订单的所有订单项;
  • 当你进行大规模选择时,连接的可扩展性通常只是一个问题。如果您选择一行,然后将其加入一些事情很少这是一个问题(但有时它是);
  • 外键应该始终被编入索引,除非你正在处理一个简单的小表;

更多Database Development Mistakes Made by AppDevelopers

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

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

因此,您需要6个联接才能从输入的用户名获得实际权限。当然可能有一个实际的要求,但是这种系统通常被放入,因为一些开发人员认为即使每个用户只有一个别名,他们可能有一天会需要它,但登录的用户是1 :1等等。一个更简单的解决方案是:

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

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

这是关于复杂性的事情:它很容易添加并且难以删除。通常它是针对意外复杂性的持续守夜,这是非常糟糕的,不会因为增加不必要的复杂性而使情况变得更糟。

答案 1 :(得分:5)

有些聪明人曾经说过:

  

归一化直到它受伤,反规范化直到它起作用!

这一切都取决于连接的类型和连接条件,但它们没有任何问题。加入ON table1.PK = table2.FK非常有效。

答案 2 :(得分:1)

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

答案 3 :(得分:0)

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

许多大型网站都为每个请求提供了会话表 http请求表,并且总是相互联系以进行页面查询。好处是参数始终与会话匹配,与适当用户的会话,用户状态始终检查,以及更多,因为它允许一些有趣的横向扩展优势。

长话故事,明智地做,但不要吝啬加入。

答案 4 :(得分:0)

正如其他人所说的那样 - 加入并不是一件可以避免的事情。事实上,在大多数模型中,很少在应用程序运行的每个查询中都没有少量连接。

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

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

  • 遍历左表中的所有值,然后一次匹配一个值到右边的值?
  • 恰恰相反?
  • 从两个表中对键进行排序并同时遍历它们?
  • 在两边建立密钥哈希?
  • 在给定加入之前或之后应用过滤条件?

因此,如果您的联接最终很复杂,那么效率将由优化程序/计划程序的复杂程度以及统计信息的货币和详细信息驱动。 MySQL在这里不是一个强有力的竞争者 - 所以我通常会保持我的模型和SQL比我使用其他东西更简单。但是每个查询的一些连接几乎总是很好。