数据库设计 - 多个查找/枚举表或一个大表?

Posted

技术标签:

【中文标题】数据库设计 - 多个查找/枚举表或一个大表?【英文标题】:Database Design - Multiple Lookup/Enum Tables or One Large Table? 【发布时间】:2010-10-26 22:27:29 【问题描述】:

我有许多表,它们的大部分列值都使用 Lookup/Enum 引用。 例如: 人员表 - PersonID |比赛代码 |头发颜色代码 |发型代码 |牙齿状况代码 位置表 - LocationID |尺码 |外观颜色代码 |条件码 Race、Size、Color、Condition 等内容只是对代码查找表的外键引用。此代码表有其他字段,但对我的问题并不重要。该数据库用于 SaaS 应用程序,这意味着每个客户都可以拥有自己的颜色、种族、条件等列表。有些代码是静态的,客户无法更改。 是有 1 个代码表还是 2 种代码表更好(DynamicCodeTable 用于客户定义的代码表,StaticCodeTable 用于更改的代码表)还是我应该为每种代码类型(RaceCodeTable、HairColorTable、Condition 等)都有一个表? 我最担心的是所有的sql连接。我正在使用的 Person 表有 20 多个这样的代码属性。加入 20 个不同的表 VS 加入同一个表 20 次时,性能是否存在差异?拥有多个表意味着每个表会更小,并且查找“应该”花费更少的时间。但是拥有一张桌子也可能很快。有什么建议吗?

【问题讨论】:

【参考方案1】:

在重新设计我们相当宽的表时,我错误地认为所有这些查找表都是一个好主意。如此多的灵活性等,但它最终变得更难编写代码,无法导航,而且这只是一个痛苦。

那么我学到了什么?

对于静态值,只需使用枚举 - 它更快、更方便。必须根据有多少其他表可能引用同一变量来做出此决定。 坚持使用更少的查找表,而不是创建尽可能多的查找表。 JOIN 的速度要慢得多。 为了帮助自己导航,设计数据库视图。它会让您的生活更轻松。 作为奖励,如果您不希望您的客户接触某些表(即静态表)或接触枚举列值,您可以使用 mysql(例如)细粒度权限来禁用对某些列的更改在某些表格中。很多人没有意识到这些权限有多灵活。

【讨论】:

我对此感到不满:如果您只使用枚举,那么它们只是您应用程序的一部分。这意味着 1) 每次查找值中的某些内容发生更改时,您都需要发布一个新版本,以及 2) 您无法在数据库上强制执行完整性(或者您必须使用混乱的 CHECK 约束“拼凑”自己的方式)。因此,我会主张对所有查找值使用查找表,而不仅仅是一个真/假字段。 或者定义你的查找表,像往常一样具有参照完整性,但是从数据库中生成你的枚举定义。这样您就可以针对枚举进行编程,并且它们与数据库匹配。【参考方案2】:

如果不了解应用程序或要求的更多信息,我建议为每种代码类型设置一个表。 IMO 数据库设计会更加清晰和自我记录,以便为您拥有的每种类型的代码提供外键。

【讨论】:

【参考方案3】:

存在潜在的性能差异。

只有 2 行的表在缓存中为这两个小行占用了大量空间。

如果您在单个表中有大量查找值,您可以 - 有效地 - 将这些值更密集地打包到缓存中。

【讨论】:

每个查找表都会比这个大。每个客户都可以有自己的一组 HairColor 代码。因此,每个客户可以有自己的 10 种颜色、10 种条件、10 种尺寸。问题是我将这 30 个代码放在一张表中还是三张表中?这些数字是针对一位客户的,理想情况下我们会有很多。因此,一百个客户可以为每个属性拥有自己的一组 10 个代码。 我完全不同意 - 如果一个表只有两列,比如 id 和 value,那么任何给定的 8k 页面上都可以容纳更多的行。我不明白你会如何那样浪费内存。我认为拥有单独、不同的查找表是一种更简洁、更“可发现”的设计,特别是对于可能在版本之间发生变化或最终用户需要在任何给定时间更改的查找值。 @marc_s:很多行“可以”适合 8k 页面。如果您在查找中只有两行,那么这两行在该页面上,没有其他内容。有效地浪费了一堆缓存空间。【参考方案4】:

在过去的 15 年中,在“一个真正的查找表”(简称 OTLT)主题下对该主题进行了详细讨论。这种方法的优势突显了数据库新手。缺点会随着时间的推移而出现。请参阅以下链接了解 OTLT 缺点:

http://tonyandrews.blogspot.com/2004/10/otlt-and-eav-two-big-design-mistakes.html http://web.archive.org/web/20100130062850/http://www.dbazine.com/ofinterest/oi-articles/celko22

或search OTLT 查找更多讨论。

如果您为它们创建了许多查找表和许多维护屏幕,您可以创建一个模拟 OTLT 的视图,方法是创建一个巨大的 UNION,其中包括每个代码、每个描述以及代码描述所在的表的名称存储对。 如果您知道自己在做什么,则可以使用半自动方法生成这样的联合。我想半自动方法可以让您为数百个查找表构建一个维护屏幕,然后在该屏幕和将在正确表中插入新代码的表之间放置一些逻辑。

至于让用户引入新的代码类型,而不仅仅是新的代码值,这会打开一大堆蠕虫。请参阅上面讨论 EAV 的文章。这很诱人,因为它允许用户设计自己的底层数据结构。如果你不考虑性能,这在一段时间内效果很好。您无需向用户或主题专家学习数据结构即可获得一个完美通用的数据库。

当它遇到真正的悲痛时,是当您尝试将数据用作集成数据库时,而不仅仅是关于数据的杂乱无章的意见的大杂烩。在这一点上,当您的客户期望生成例行报告时,您就进入了一些严肃的数据考古领域。祝你好运。

(编辑将“数据挖掘”改为“数据考古”)

【讨论】:

以上是关于数据库设计 - 多个查找/枚举表或一个大表?的主要内容,如果未能解决你的问题,请参考以下文章

关于列族数量的大表设计和查询

MySQL 对于千万级的大表要怎么优化

术语:在 OOP 中,当您有一个对象或记录使用来自查找表或网关的“连接”数据时,它叫啥?

查找表或视图的依赖对象

sqlserver数据将多个表或视图的数据合并到一个表或视图里的sql语句

哪个更高效:多个 MySQL 表还是一个大表?