AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 193292
Accepted
Arthur Tarasov
Arthur Tarasov
Asked: 2017-12-17 00:27:03 +0800 CST2017-12-17 00:27:03 +0800 CST 2017-12-17 00:27:03 +0800 CST

构建尽可能多的外键是一种好习惯吗?

  • 772

例如,有三个表:players、dungeons和instances。

一个player有很多dungeons,一个dungeon有很多instances,就像一个著名的魔兽世界游戏。每个player都有一个dungeon_id作为外键,每个dungeon都有一个instance_id作为外键。那将是一种足够的极简主义方法。player每一个都instance可以通过dungeon表访问。这将减少 1 列,但查询时间更长。

另一种方法是作为外键添加player_id到表中。instances现在玩家可以直接从instances表中查询。更短的查询,但外键多一列。

从长远来看,哪种方法更好?在实践中,似乎在逻辑上可能的任何地方都添加外键会更容易。但是这不会导致更紧密的耦合并使代码更难重构吗?

foreign-key
  • 2 2 个回答
  • 2045 Views

2 个回答

  • Voted
  1. KumarHarsh
    2017-12-17T03:14:47+08:002017-12-17T03:14:47+08:00

    另一种方法是将 player_id 作为外键添加到实例表中。现在玩家可以直接从实例表中查询。更短的查询,但外键多一列。

    IMO,这将是不好的方法。这是一种循环引用。

    由于您有一对多关系,因此映射表将是分开的,地牢、实例和玩家每个都将具有定义其一对多关系的主表和映射表。

        CREATE TABLE instances (
        instance_id INT PRIMARY KEY
        ,instance VARCHAR(100) NOT NULL
        )
    
    CREATE TABLE dungeons (
        dungeon_id INT PRIMARY KEY
        ,dungeon VARCHAR(100) NOT NULL
        )
    
    CREATE TABLE player (
        playerid INT PRIMARY KEY
        ,player VARCHAR(100) NOT NULL
        )
    
    
    CREATE TABLE dungeon_instance (
        dungeon_instance_id INT identity(1, 1)
        ,dungeon_id INT NOT NULL
        ,instance_id INT NOT NULL CONSTRAINT FK_instances FOREIGN KEY (instance_id) REFERENCES instances(instance_id)
        ,CONSTRAINT FK_dungeon FOREIGN KEY (dungeon_id) REFERENCES dungeons(dungeon_id)
        ,PRIMARY KEY (
            dungeon_id
            ,instance_id
            )
        )
    
    CREATE TABLE player_dungeon (
        player_dungeon_id INT NOT NULL
        ,playerid INT NOT NULL
        ,dungeon_id INT NOT NULL
        ,CONSTRAINT FK_player FOREIGN KEY (playerid) REFERENCES player(playerid)
        ,CONSTRAINT FK_dungeon FOREIGN KEY (dungeon_id) REFERENCES dungeons(dungeon_id)
        ,PRIMARY KEY (
            playerid
            ,dungeon_id
            )
        )
    

    如果您在播放器和实例之间有非常频繁的查询,并且输出中不需要地牢表并且数据量很高,那么您可以进行非规范化。

    是否创建player_instance mapping table取决于上述要求。

    但希望通过以下方式实现非规范化index view

    • 1
  2. Best Answer
    DecoderReloaded
    2017-12-17T03:45:01+08:002017-12-17T03:45:01+08:00

    理想情况下,实体不应该有外键,应该被认为是主人。所以player,dungeon并且instance是拥有与他们自己的特征相关的信息/属性/字段的大师。您可以为Enitity-Relations提供一个单独的表。因此,您将拥有player_dungeonand dungeon_instance(根据 PS,两者都是一对多)。在这里,如果你想知道instances属于一个player,你需要加入这两个表。

    现在出现了著名的辩论:规范化与非规范化。第一种方法是书本上的,并且会奏效。但是随着表的增长很难扩展(尽管有适当的索引)。因此,您尝试根据这些表上发生的查询量对上述解决方案进行非规范化。

    player每一个都instance可以通过dungeon表访问。

    由于您在此处指定了一个查询,我假设这是一个频繁查询(瓶颈)。如果有很多这样的查询,你可以有另一个关系表player_instance。现在我们已经解决了延迟的问题,但产生了一个更大的问题:

    一致性:现在有两种方法可以找到instances属于 a 的player。一种是直接按player_instance表,另一种是通过player_dungeon和连接dungeon_instance。我们必须始终从这两种方法中得到相同的答案。为了确保我们现在需要让我们的写入受到影响。如何?

    • 在添加每个玩家-地牢映射时,除了进入我们的 player_dungeon表之外,我们还需要插入到player_instance 表中(我们必须查询dungeon_instance以查看映射到该特定地牢的所有实例)。
    • 在添加新dungeon_instance玩家时,我们需要将所有现有玩家映射到我们映射到特定地牢的实例。听起来不太好,是吗?

    我们还没有完成。所有这些操作都应该是原子的(即在事务中),否则会在短时间内出现不一致。

    最后,我们需要做出取舍。您想让您的数据库读取速度变慢还是写入受到影响?您是否需要使您的系统响应/可用或一致?决定权在你。

    详情请阅读CAP 定理。

    • 1

相关问题

  • 如何规范化时间表数据?

  • 删除/更新外键约束中 SET NULL 的目的是什么?

  • 固定值字段的外键约束

  • 非唯一多列外键

  • 外键违规 - 不知道为什么

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve