【问题标题】:Consolidating tables with one-to-one relationships合并具有一对一关系的表
【发布时间】:2011-04-27 21:20:37
【问题描述】:

我有 3 个用于会员系统的 MySQL 表。

  • users:最低要求是用户,仅与帐户信息(电子邮件、密码、is_activated 等)有关
  • user_profiles:用户提供的个人信息(姓名、地址、电话……)
  • user_member_profiles:管理员严格管理信息(缴纳注册费、参加会议等)

这些可以压缩到一张表中,让我省心并保持我的代码干净 - 但我觉得最好将它们分开,因为它们的用途略有不同。

选项 1: 保持这种状态,继续做 JOINs 和乏味的 UPDATEs (这段数据放在这张桌子上,这块放在另一张桌子上,等等.)。对我来说有更多的工作,但也许更有意义?

选项 2:将所有内容合并到一张表中。

我认为使用一张表会更快,无需连接表。也许这取决于数据?每个表大约有 12-20 个字段,因此合并后的表会很大。

每个用户在每个表中的个人资料不超过 1 个,但甚至可能根本没有个人资料(或总共可能只有 1 个)。

为此添加一点上下文:它适用于用 PHP 编写的不断发展的 CMS,我需要对每次安装的表进行调整。管理员需要以类似电子表格的方式管理成员,因此我一次最多选择 200 个用户。

从性能、设计或组织的角度来看,正确的方法是什么?

【问题讨论】:

  • 无论表结构如何,您都应该始终只选择您需要的内容!我看不出这几个连接会成为一种负担。
  • 选项 2 的一部分,“请确保只选择我需要的内容”,似乎与“我还需要每次都从每个配置文件表中选择 * 因为我需要每个可用字段。”
  • @Catcall:我的意思是当我需要来自一个配置文件的数据时,我需要所有数据,但我并不总是需要来自任何配置文件的数据。
  • @HLGEM:是的,我明白了,但是我发现 JOIN 语句比从一个表中进行简单查询花费的时间更多,并且它使管理执行更新变得更加困难(来自 html 表单中的应用程序),因为我必须挑选每个字段并确保它进入正确的配置文件表。
  • 如果您的连接语句很慢,那么您需要确保正确的索引到位。数据库经过优化以进行连接,但您必须进行正确设置。

标签: mysql database database-design relational-database


【解决方案1】:

宽表(多列)要考虑的另一个因素是对 RDBMS 缓存的影响。任何优秀的开发人员都知道您不会执行“从表中选择 *”,因为它会通过网络将不必要的数据从 RDBMS 传送到客户端。但是类似的效果可能发生在磁盘和 RAM 之间,并且还会影响一个表需要缓存的 RAM 空间量。

大多数 RDBMS 分配给定的内存量来缓存数据,从而减少物理磁盘读取并加快对用户的响应。这是 Oracle 或 SQL Server 中的缓冲区缓存

如果您有一个宽表并以“从表中选择 col1、col2、col3”的形式发出查询,RDBMS 会将整个行加载到 RAM(不是 col1 到 3)。当它这样做时,它会老化较旧的缓存数据。如果您的表格很宽并且您加载 50 列,那么您当然需要比相同数量的行 * 窄表格更多的 RAM。这会对 RDBMS 性能产生显着影响。

大量宽表,缓存中的其他表老化,并且可能会看到 IO 统计数据彻底消失,因为常用表老化超出缓存以为宽表腾出空间。

这个因素应该被添加到规范化数据的其他优点中,并在表设计时考虑。实际上,如果您有一个可能很宽的表,其中一些数据会定期访问,而另一些数据很少访问,请考虑具有 1 对 1 关系的多个表。

【讨论】:

  • 您提出了一些我不知道的有趣技术点:SELECT * FROM multiple tables 比 SELECT col1,col2,col3 from a single table 要快。在寻找将数据分成不同表的方法之前,您认为最大列数是多少? (假设这是可能的,并且数据不是很紧密相关)
  • 重新阅读您的答案后,它更有意义。如果这里有一个逗号:rarely**,** consider,那就更清楚了。我把它读作“很少考虑”。非常感谢这个建议,正如我所料,我们将坚持原来的设计。我想也许我以这种方式拆分数据太“防守”了,有人会过来说“没有必要这样做。”
【解决方案2】:

我的设计建议说保持分离,因为将来用户可能会有两个配置文件,但如果将它们合并,性能可能会更好。如果真的存在一对一的关系,并且这种关系永远不会改变,那么我会将它们合并。

【讨论】:

  • 是的。第一种形式似乎更适合标准化。如果您需要 3 个表中的列,第二个会更快。如果您的主要目标是简化查询,请创建一个视图。
  • 没想到观点。这肯定会有所帮助。
  • 可以肯定地说,用户永远不会有两个配置文件,但有些用户只需要一个。另一个问题是该表至少有 50 列,据我所知,这听起来像是糟糕的设计;但话又说回来:你必须做你必须做的事。 “视图”的概念现在超出了我的完全理解,这是一个好的解决方案还是只是另一种选择?
  • 出于简单的需要,我使用了超过 40 列的表。视图通常旨在为某些用户提供对某些数据的特定访问权限,但这并不是使用它们的唯一方式。对你来说,这可能只是另一种选择。
  • 请参阅我在下面添加的关于宽表对性能影响的答案。除了删除插入和更新异常之外,还要考虑性能。
【解决方案3】:

您不必使用那么多连接来检索数据。

您可以使用VIEW 来显示来自usersuser_profiles 的所有列:

CREATE VIEW users2 AS
( SELECT u.id
       , u.email
       , u.password
       , u.is_activated
       , p.name
       , p.address
       , p.phone
  FROM users u
    LEFT JOIN user_profiles p
      ON u.id = p.id
)

并在需要来自两个表的数据的查询中使用此视图。所有 3 个表的另一个 VIEW 等。

【讨论】:

  • 谢谢大家,看来大家都建议使用视图,这是我需要学习的东西。这与简单地用一张大表编写简洁的 SELECT 语句有什么区别?通过将数据保存在单独的表中,我是在“做正确的事”还是没关系?
【解决方案4】:

设计问题是您是否需要在任何这些表中为一个用户提供多条记录。如果是这样,请不要合并它们。如果表是一对一的关系,您可以组合它们,但如果它们有很多字段或者您的记录大小太宽,这可能会导致性能问题,并且如果您无法添加数据,则不应该超过单个记录的实际记录大小限制。如果您当前有很多代码可以将它们作为 serrate 表和大量数据进行访问,请重组它们以获得您将获得的微小收益(在开发中节省一分钟左右的时间,并且可能完全没有时间给用户带来性能下降)似乎是个坏主意。您可以编写视图,因此您不必进行连接,但老实说,这些非常简单,我也不会在那里打扰。

【讨论】:

  • saving all of a minute or so in development:这对我来说在代码清晰和简化方面实际上很重要,实际上最终会超过一两分钟随着事情的发展而我需要,例如,添加更多字段或以不同方式管理它们。 probably no time at all inperformance to the users:有时我需要展示数百个用户(用于管理),所以我实际上对获得更好的性能很感兴趣。您是说视图不值得花时间/精力,还是说这不是使用它们的好理由?
  • 我是说视图对于复杂的关系而不是像这样的简单关系很有用。我也倾向于避免使用视图,因为人们对它们很着迷,并创建调用其他视图的视图,这可能会产生可怕的性能问题。这并不是一个很难的场景,创建一个视图可以为任何人节省任何东西,它只是增加了一个不需要的抽象级别,基本上没有任何收获。
  • 好的,我现在明白(并同意)谢谢。这很简单。基本上有4种场景:访问table1,table1+table2,table1+table3,或者table1+2+3。我总是需要访问表中的所有数据。我想知道我是否应该保持原样并使用 JOIN 选择 *,或者将所有内容放在一个表中,然后为这 4 个实例中的每一个选择我需要的列。听起来你的建议是按照我的方式保留,对吗?
  • 是的,除非我永远不会使用 select *,您需要指定列。 Select * 是一种非常糟糕的编程技术,不应在生产代码中使用。这是一个草率的坏习惯。 Select * 可能会在结构更改时导致严重错误(例如,某些人添加了您不希望用户看到的列,或者将插入语句弄乱到另一个表中)并导致性能问题。当你有一个连接时,你至少有一列包含相同的数据,你要返回两次,这会浪费网络和服务器资源。
【解决方案5】:

将表分开有两个原因,都与您为每个用户保留多少记录有关。

  • 如果每个人都有多个个人资料,请将用户和个人资料数据分开;使用配置文件表(关系的多方)中的列来引用用户表的主键。
  • 如果每个人都可以选择拥有个人资料(即有个人资料或没有个人资料),请以相同的方式使用两个表,但要使连接更容易,请在两个表中使用相同的主键。目的是避免有很多空行的表。另一种思考方式是配置文件继承自 person - 因此使用具有相同键的添加数据表。

除了这种情况,您希望用一把钥匙将所有东西都放在一张桌子上。为了表达数据的多种用途,一个好的解决方案是使用视图 - 选择数据的子集并将其保留为视图,并具有合理的名称。当您需要管理数据时,请调用相应的视图。

【讨论】:

  • 同一个表中没有多个配置文件。您的另一个要点真的是“将桌子分开的原因”吗?如果我能够按照大家的建议使用视图,那么当我的数据已经分散到多个表中时,一个大表的意义何在?
  • 一张表将意味着某事的数据放在一起。所以 user 表中的每一行都是一个用户,如果表设计得很好,每个用户的所有内容都是一行,由一列或几列和其他列组成的明确 id 用于额外信息。
【解决方案6】:

除非您遇到奇怪的性能问题,否则您应该只有一张桌子。

我所说的性能问题是指拥有如此多的数据,以至于您希望将其跨表分区以使其保持独立(物理磁盘、服务器等)。这显然不是这里的情况。如果是这样,那么有很多更好的方法来处理这种事情。

每个人都希望他们遇到的那种性能问题,但很少有人这样做......

【讨论】:

  • 我并没有太多“有性能问题”,因为我正在尝试加快速度并使其更易于在应用程序中进行管理。 Unless you're having performance issues, you should just have one table. - 所以你是说如果我没有性能问题,我应该使用一个表,但是如果我am有问题,我应该使用几个表??? there are better ways to deal with it - 不知道你指的是什么,能指教一下吗?
  • 我的意思是非常奇怪的性能问题而不是正常问题,我过度保护了我的答案。道歉。我会相应调整。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-01
相关资源
最近更新 更多