在其他表可以使用连接进行连接时,在单个表中使用多个外键是好还是坏?

时间:2014-08-05 18:58:55

标签: mysql sql sql-server database join

假设我想建立一个可用于跟踪用户的银行账户和交易的数据库。可以在Checkbook应用程序中使用的数据库。

如果我有一个用户表,则具有以下属性:

  1. USER_ID
  2. 电子邮件
  3. 密码
  4. 然后我创建了一个帐户表,可以链接到某个用户:

    1. ACCOUNT_ID
    2. ACCOUNT_DESCRIPTION
    3. account_balance
    4. USER_ID
    5. 为了进行下一步,我创建了一个事务表:

      1. 的transaction_id
      2. transaction_description
      3. is_withdrawal
      4. account_id //此交易所属的帐户
      5. user_id //此交易所属的用户
      6. 在事务表中使用user_id是一个不错的选择吗?如果我想获得每个用户的所有事务,它将使查询更清晰,例如:

        SELECT * FROM transactions
        JOIN users ON users.user_id = transactions.user_id
        

        或者,我可以追溯到帐户表中的users表

        SELECT * FROM transactions
        JOIN accounts ON accounts.account_id = transactions.account_id
        JOIN users ON users.user_id = accounts.user_id
        

        我知道第一个查询更清晰,但这是最好的方法吗?

        我担心的是,通过在事务表中使用这个额外的(冗余)列,我浪费了空间,当我可以在没有列的情况下获得相同的结果时。

5 个答案:

答案 0 :(得分:3)

让我们从不同的角度来看待它。查询或一系列查询从哪里开始?如果您有客户信息,您可以获得帐户信息,然后获取交易信息或只是每个客户的交易。您需要所有三个表来获取有意义的信息。如果您有帐户信息,则可以获取交易信息和指向客户的指针。但是要获取任何客户信息,您需要转到客户表,因此您仍然需要所有三个表。如果您有交易信息,您可以获得帐户信息,但没有客户信息就没有意义,或者您可以在没有帐户信息的情况下获得客户信息,但是每个客户的交易都是没有帐户数据的无用噪音。

无论哪种方式对其进行切片,任何可以想象的使用所需的信息都会在三个表之间分开,您必须访问这三个表才能获得有意义的信息,而不仅仅是数据转储。

在交易表中拥有客户FK可能会为您提供一种“干净”查询的方法,但该查询的结果具有可疑性。所以你真的什么都没得到。我曾为国际信用卡公司编写反洗钱(AML)扫描仪,所以我不是假设。无论如何,你总是需要所有三张桌子。

Btw,首先有FK的事实告诉我这个问题涉及OLTP环境。 OLAP环境(数据仓库)不需要FK或任何其他数据完整性检查,因为仓库数据是静态的。数据源自已进行数据完整性检查的OLTP环境。所以你可以对你的心灵内容进行反规范化。因此,我们不要将适用于OLAP环境的答案提供给有关OLTP环境的问题。

答案 1 :(得分:2)

您不应在同一个表中使用两个外键。这不是一个好的数据库设计。

用户通过帐户进行交易。这就是逻辑上的完成方式;因此,这就是数据库的设计方式。

使用连接是如何做到的。您不应该使用user_id密钥,因为它已经存在于帐户表中。

浪费的空间是不必要的,是一个糟糕的数据库设计。

答案 2 :(得分:2)

非规范化通常是一个坏主意。首先,从性能标准来看,它通常不会更快。它的作用是使数据完整性处于危险之中,如果你最终从1-1关系变为1-many,它可能会产生大量问题。

例如,每个帐户只有一个用户?在你的桌面设计中,你会得到的是我发现可疑的东西。我系统中的帐户可以拥有数千个用户。这是我对你的模型提出质疑的第一个地方。您是否真的认为实际情况是1-1还是1-many?或者你刚刚做出了什么?拥有数百万条记录后,数据模型不易调整,您需要为数据库设计的未来做更多的规划,并且比应用程序设计中更多地考虑数据需求。

但是假设你现在有一对一的关系。在您上线三个月后,您将获得一个新帐户,他们需要拥有3个用户。现在,您必须记住您重新命名的所有位置才能正确修复数据。这会造成很多混乱,因为你不可避免地会忘记其中的一些。

此外,即使您永远不需要转移到更强大的模型,如果user_id经常更改,您将如何维护它?现在,为了保持数据完整性,您需要有一个触发器来保持数据的变化。更糟糕的是,如果可以从任何一个表更改数据,您可能会收到相互冲突的更改。你是如何处理这些的?

所以你创造了一个维护混乱,并可能冒险将你的数据完整性写成"更清洁"代码并保存自己十秒钟写一个连接?对于在数据库开发中很重要的事情,例如性能或安全性或数据完整性,你什么都得不到,而且你冒了很多风险。这有多短视?

你需要停止思考"清洁代码"什么时候开发数据库。通常,查询的最佳代码是最复杂的,因为它是最高性能的,对数据库而言至关重要。不要将面向对象的编码技术投射到数据库开发中,它们是两个非常不同的东西,需求非常不同。您需要开始思考这将如何发挥作用,因为您明显没有做的数据更改,或者您甚至不会考虑做这样的事情。您需要更多地考虑数据意义,而不是更多的软件开发原则"它们被教导好像它们适用于所有东西,但实际上并不适用于数据库。

答案 3 :(得分:1)

这取决于。如果您可以足够快地获取数据,请使用规范化版本(其中user_id不在事务表中)。如果您担心性能,请继续并包含user_ID。通过存储冗余信息,它将在数据库中占用更多空间,但您将能够更快地返回数据。

修改

在决定是否对数据结构进行非规范化时,需要考虑几个因素。每种情况都需要被认为是唯一的;没有回答具体情况就没有答案是足够的(因此,“这取决于”开始这个答案)。对于上面的简单情况,非规范化可能不是最佳解决方案。

答案 4 :(得分:1)

在我看来,如果你有简单的多对多关系,只需使用两个主键即可。

否则,如果您与额外列有多对多关系,则使用一个主键和两个外键。像单一实体一样管理这个表更容易,就像Doctrine那样。一般来说,简单的“多对多”关系很少见,它们仅用于链接两个表。