如何管理数据库中多个表之间的公共信息

Posted

技术标签:

【中文标题】如何管理数据库中多个表之间的公共信息【英文标题】:how to manage common information between multiple tables in databases 【发布时间】:2022-01-11 20:32:30 【问题描述】:

这是我关于堆栈溢出的第一个问题,我是一名全栈开发人员,我使用以下堆栈:Java - spring - angular - mysql。我正在做一个附带项目,我有一个数据库设计问题。

我有一些在多个表之间共有的信息,例如:

文档信息(最初可用于 FOLDER 和 CONTRACT 表)。 类型信息(表:COURT、FOLDER、OPPONENT,...)。 状态(表格:合同、文件夹...)。 地址(表:OFFICE、CLIENT、OPPONENT、COURT,...)。

为了避免重复并将核心表与“技术”表(可在许多表中使用的信息)耦合。我正在考虑将“技术”表合并到一个功能表中。例如,我们可以有一个包含以下列的通用 DOCUMENT 表:

身份证 标题 描述 创建日期 TYPE_DOCUMENT(文件夹、合同...) OBJECT_ID(TYPE_DOCUMENT 表的主键) OFFICE_ID PATT_DATA

例如,我们可以使用以下查询检索有关文档的信息:

SELECT * FROM DOCUMENT WHERE OFFICE_ID = "office 1 ID" AND TYPE_DOCUMENT = "CONTRACT" AND OBJECT_ID= "contract ID";

我们还可以使用以下索引来优化查询: CREATE INDEX idx_document_retrieve ON DOCUMENT (OFFICE_ID, TYPE_DOCUMENT, OBJECT_ID);

我的问题是:

这是个好设计吗? 有没有更好的方法来实现这个设计。 我应该只使用普通的数据库设计吗,例如一个文件夹可以 有很多文档,所以我创建了一个 folder_document 表 folder_id 作为外键。并对所有表格执行相同操作。

非常欢迎任何建议或注释,并提前感谢您的帮助。

【问题讨论】:

【参考方案1】:

您所描述的内容听起来像是您正在尝试决定是否要进行非规范化以及要进行多少非规范化。

答案是:这取决于您的查询。非规范化使对数据执行某些查询变得更方便或更高效,但代价是执行其他查询变得更加困难或效率低下。这也使得保持冗余数据同步变得困难。

因此,您希望最小化非规范化,并且仅在它为您需要优化的查询提供良好优势时才这样做。

规范化优化数据关系。这使得数据库组织不会针对任何特定查询进行优化,但同样适合您的所有查询,并且还具有防止数据异常的优势。

非规范化针对特定查询进行优化,但以牺牲其他查询为代价。您可以自行决定哪些查询需要优先处理,哪些查询可能会受到影响。

如果您无法确定哪些查询值得优先考虑,或者您无法预测将来是否会有其他新查询,那么您应该坚持规范化设计。

Stack Overflow 上的任何人都无法比您更了解您的查询。

【讨论】:

【参考方案2】:

案例一:status

“状态”通常是一个值。为了使其可读,您可以使用ENUM。如果您需要有关状态的更多信息,可以使用带有 PRIMARY KEY(status) 的单独表格以及有关状态的其他列。

案例 2:address

“地址”很庞大,可能有多个列。 (然而,由于在WHEREORDER BY 子句中很少需要“地址”的组成部分,所以除了TEXT 和嵌入的换行符之外,几乎没有充分的理由使用它。

但是,“addressis usually implemented as several separate fields. In this case, a separate table is a good idea. It would have a columnid MEDIUMINT UNSIGNED AUTO_INCREMENT PRIMARY KEYand the various columns. Then, the other tables would simply refer to it with anaddress_idcolumn andJOIN` 在需要时添加到该表。即使许多表都有地址,这也很干净并且效果很好。

一个警告:当您需要更改某些实体的地址时,如果您已经删除了地址,请小心。最好总是添加一个新地址并为不再需要的地址浪费空间。

讨论

这两种情况(状态和访问)可能是极端情况。对于每个潜在的公共列,决定哪个更有意义。正如比尔指出的那样,您确实需要考虑查询才能使架构“正确”。您必须在决定除PRIMARY KEY 之外的索引之前编写主要查询。 (所以,我现在不会解决您关于索引的问题。)

不要将 4 字节的 INT 用于小的、大部分不可变且更易于阅读的内容:

2 字节 country_code(美国、英国、日本……) 5字节zip-code CHAR(5) CHARSET ascii;类似 6 字节 postal_code 1 字节 `ENUM('maybe', 'no', 'yes') 1 字节 `ENUM('not_specified', 'Male', 'Female', 'other');如果您尝试枚举所有“其他人”,这可能不太好。 1字节ENUM('folder', ...)

您的“文件夹”与“文档”是一对多关系的一个示例。是的,它是通过在表Folders 中添加doc_id 来实现的。

“多对多”需要一个额外的表来连接两个表。

枚举

有些人会反对使用ENUM。在您的情况下,无法确保每个表都使用相同的定义,例如doc_type。在列表末尾添加一个新选项很容易,但重新排列ENUM 的成本很高。

ID

id(或ID)几乎被普遍保留(按照惯例)表示表的PRIMARY KEY,通常(但不一定)是AUTO_INCREMENT。请不要违反此约定。请注意,在上面的示例中,idAddresses 表的 PK,但在引用表中称为 address_id。您可以选择性地在两个表之间创建FOREIGN KEY

【讨论】:

以上是关于如何管理数据库中多个表之间的公共信息的主要内容,如果未能解决你的问题,请参考以下文章

如何使用公共列从多个表中检索数据

连接查询

如何定义游标,当我们在两个表之间有一个公共列而不给出别名时

两个表中具有多个公共属性的自然连接[重复]

MySQL8:连接查询

连接查询