数据库设计问题,不通过外键如何维护关系


现在有几张表:学生表、班级表、专业表、院系表

其中学生信息要实现批量导入功能,导入的信息中的班级、专业、院系等都是名称,而不是id,所以在学生表中没有班级、专业、院系的外键,是直接在三个字段中存入名称。但是在其他地方还要用到班级、专业、院系的信息,所以这三个必须建表。这样怎么保证学生表和其他三个表中数据的一致性。

数据库 数据库性能优化 数据库设计

re洗鐵路 10 years, 10 months ago

对于这个简单的系统, 班级、专业、院系都用字符串存储是没有问题的, 而且简化了你的业务逻辑. 只有在班级、专业、院系修改时出现了数据的不同步. 但这种情况不不常见, 也不难解决.
如果将班级、专业、院系都转化为ID来存储, 那么占用更少的空间, 但使用每次读取都要连接表才能显示出来.新增,更新, 删除这些字段都变得复杂了. 用ID来存储的另外一个问题是存档, 用户可能会提问, 为什么软件上看到的资料跟自己以前打印出来的纸质版不同. 例如有个人从1班调到2班了, 那么你连接出来的资料全部变成了2班的, 这是需要考虑考虑了.

有情人终成兄妹 answered 10 years, 10 months ago

你应该在学生表里面存班级、专业和院系的 id,如果为了方便展示,也可以存入班级、专业和院系的名字。

一般来说(我指的是要面向很多用户的互联网产品)我们不会使用数据库的 forign key 功能,而是采用程序逻辑来维护这些东西的一致性,比如在修改班级名称的时候也记得把 所有 存了班级名称的数据全部修改过来。这里面并没有什么巧,就是简单的通过程序逻辑(甚至是程序员的自觉性)来保证。

总之,没什么好建议,如果要这么做,小心的写代码吧。

最爱豆沙包 answered 10 years, 10 months ago

泻药。

数据一致性墨菲定律: 任何数据只要存储了超过 1 次,那么数据的一致性就算再精心维持,也迟早会受到破坏,没有例外

真正有效的文本数据 应当并仅允许存储 1 次 。关系 应当并仅允许使用ID来维持 。任何冗余的数据都只应当用作缓存。学生表中必须只存储班级·专业·院系的ID。这一点没有任何的商量。

应对其他的需求,应当在程序设计方法上见招拆招,而不是动摇数据库设计的原则——

  • 导入时应当识别班级·专业·院系的名称并转换为ID。
  • 在学生表格的最后加入一个缓存列,存储班级·专业·院系的名称用于显示时快速调用,而不应当拆掉学生表格原本的结构。
  • 缓存列任何时候想刷掉就刷掉,绝对禁止视为有效数据,如果可能应当禁止导出。重要场合应当强制刷新甚至禁止缓存。
  • 缓存不是人应该看的东西,在数据表中占地越少越好。比如这个需求,缓存数据就应当用 JSON 编码后挤在 1 列里,而不应当啰嗦的存 3 列。
  • 考虑到班级·专业·院系名称种类相对较少,记录变动也不频繁,也可以考虑使用Redis/Memcached等各种缓存方案。

最后提一下:数据库的 外键 约束可以使用,但绝对不能作为维持数据关系的可靠方法,只能在小规模数据库中作为兜底的手段。断不可写出“ try { $record->insert(); } catch (MySQLForeignKeyException $e) { ... } ”这样的代码。

NP.梦魇 answered 10 years, 10 months ago

Your Answer