如何管理数据库中多个表之间的公共信息
how to manage common information between multiple tables in databases
这是我关于 stack-overflow 的第一个问题,我是一名 full-stack 开发人员,我使用以下堆栈:Java - spring - angular - MySQL。我正在做一个副项目,我有一个数据库设计问题。
我有一些信息在多个 table 之间是通用的,例如:
- 文件信息(最初可用于FOLDER和CONTRACT
tables).
- 输入信息(tables: COURT, FOLDER, OPPONENT, ...)。
- 状态(tables:合同、文件夹...)。
- 地址(tables:办公室、客户、对手、法院...)。
为了避免重复和耦合核心 table 与“技术”table(可以在许多 table 中使用的信息)。我正在考虑将“技术”table 合并为一个功能 table。例如,我们可以有一个包含以下列的通用 DOCUMENT table:
- ID
- 标题
- 描述
- CREATION_DATE
- TYPE_DOCUMENT(文件夹、合同...)
- OBJECT_ID(TYPE_DOCUMENTTable的主键)
- OFFICE_ID
- PATT_DATA
例如,我们可以使用以下查询检索有关文档的信息:
SELECT * FROM DOCUMENT WHERE OFFICE_ID = "office 1 ID" AND TYPE_DOCUMENT = "CONTRACT" AND OBJECT_ID= "contract ID";
我们还可以使用下面的索引来优化查询:
在文档上创建索引 idx_document_retrieve (OFFICE_ID, TYPE_DOCUMENT, OBJECT_ID);
我的问题是:
- 这个设计好吗
- 有没有更好的方法来实现这个设计。
- 我应该只使用普通的数据库设计吗,例如文件夹可以
有很多文档,所以我创建了一个 folder_document table
folder_id 作为外键。并对所有 table 执行相同的操作。
非常欢迎任何建议或注意事项,并提前感谢您的帮助。
您所描述的内容听起来像是您在尝试决定是否反规范化以及反规范化的程度。
答案是:这取决于您的查询。非规范化使得对您的数据执行某些查询更加方便或性能更高,但代价是使其他查询变得更难或效率更低。这也使得冗余数据很难保持同步。
所以您希望最小化非规范化,并且仅当它在您需要优化的查询中为您提供良好优势时才这样做。
规范化优化数据关系。这使得数据库组织不会针对任何特定查询进行优化,但同样适合您的所有查询,并且还具有防止数据异常的优势。
非规范化针对特定查询进行优化,但以牺牲其他查询为代价。您需要知道哪些查询需要优先处理,哪些查询可能会受到影响。
如果您无法决定哪些查询值得优先处理,或者您无法预测将来是否会有其他新查询,那么您应该坚持使用规范化设计。
Stack Overflow 上没有任何人比您更了解您的查询。
案例一:status
“状态”通常是单个值。为了使其可读,您可以使用 ENUM
。如果您需要有关状态的更多信息,可以使用单独的 table 和 PRIMARY KEY(status)
以及有关状态的其他列。
案例二:address
“地址”体积庞大,可能有多列。 (但是,由于 WHERE
或 ORDER BY
子句很少需要“地址”的组成部分,所以很少有充分的理由以 TEXT
以外的任何形式使用它,并且嵌入换行符。
但是,“addressis usually implemented as several separate fields. In this case, a separate table is a good idea. It would have a column
id MEDIUMINT UNSIGNED AUTO_INCREMENT PRIMARY KEYand the various columns. Then, the other tables would simply refer to it with an
address_idcolumn and
JOIN` 需要时 table . 这很干净,即使许多 table 都有地址也能正常工作。
一个警告:当您需要更改某个实体的地址时,如果您已经删除了重复地址,请小心。最好总是添加一个新地址,并将 space 浪费在任何不再需要的地址上。
讨论
这两种情况(状态和访问)可能是极端情况。对于每个可能常见的列,决定哪个更有意义。正如 Bill 指出的那样,您确实需要考虑查询才能获得架构 'right'。在决定 PRIMARY KEY
以外的索引之前,您 必须 编写主要查询。 (所以,我现在不会回答你关于索引的问题。)
不要使用 4 字节 INT
来表示小的东西,主要是 immutable,并且更容易阅读:
- 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', ...)
您的“文件夹”与“文档”是一对多关系的示例。是的,它是通过在 table Folders
.
中设置 doc_id
来实现的
“多对多”需要额外的 table 来连接两个 table。
枚举
有些人会反对使用 ENUM
。在您的情况下,无法确保每个 table 使用相同的定义,例如 doc_type
。在列表 的末尾添加一个新选项 很容易,但重新排列 ENUM
.
的成本很高
ID
id
(或 ID
)几乎普遍保留(按照惯例)表示 table 的 PRIMARY KEY
,通常(但不一定) AUTO_INCREMENT
。请不要违反这个约定。请注意,在我上面的示例中,id
是 Addresses
table 的 PK,但在引用 table 中调用了 address_id
。您可以选择在两个table之间创建一个FOREIGN KEY
。
这是我关于 stack-overflow 的第一个问题,我是一名 full-stack 开发人员,我使用以下堆栈:Java - spring - angular - MySQL。我正在做一个副项目,我有一个数据库设计问题。
我有一些信息在多个 table 之间是通用的,例如:
- 文件信息(最初可用于FOLDER和CONTRACT tables).
- 输入信息(tables: COURT, FOLDER, OPPONENT, ...)。
- 状态(tables:合同、文件夹...)。
- 地址(tables:办公室、客户、对手、法院...)。
为了避免重复和耦合核心 table 与“技术”table(可以在许多 table 中使用的信息)。我正在考虑将“技术”table 合并为一个功能 table。例如,我们可以有一个包含以下列的通用 DOCUMENT table:
- ID
- 标题
- 描述
- CREATION_DATE
- TYPE_DOCUMENT(文件夹、合同...)
- OBJECT_ID(TYPE_DOCUMENTTable的主键)
- OFFICE_ID
- PATT_DATA
例如,我们可以使用以下查询检索有关文档的信息:
SELECT * FROM DOCUMENT WHERE OFFICE_ID = "office 1 ID" AND TYPE_DOCUMENT = "CONTRACT" AND OBJECT_ID= "contract ID";
我们还可以使用下面的索引来优化查询: 在文档上创建索引 idx_document_retrieve (OFFICE_ID, TYPE_DOCUMENT, OBJECT_ID);
我的问题是:
- 这个设计好吗
- 有没有更好的方法来实现这个设计。
- 我应该只使用普通的数据库设计吗,例如文件夹可以 有很多文档,所以我创建了一个 folder_document table folder_id 作为外键。并对所有 table 执行相同的操作。
非常欢迎任何建议或注意事项,并提前感谢您的帮助。
您所描述的内容听起来像是您在尝试决定是否反规范化以及反规范化的程度。
答案是:这取决于您的查询。非规范化使得对您的数据执行某些查询更加方便或性能更高,但代价是使其他查询变得更难或效率更低。这也使得冗余数据很难保持同步。
所以您希望最小化非规范化,并且仅当它在您需要优化的查询中为您提供良好优势时才这样做。
规范化优化数据关系。这使得数据库组织不会针对任何特定查询进行优化,但同样适合您的所有查询,并且还具有防止数据异常的优势。
非规范化针对特定查询进行优化,但以牺牲其他查询为代价。您需要知道哪些查询需要优先处理,哪些查询可能会受到影响。
如果您无法决定哪些查询值得优先处理,或者您无法预测将来是否会有其他新查询,那么您应该坚持使用规范化设计。
Stack Overflow 上没有任何人比您更了解您的查询。
案例一:status
“状态”通常是单个值。为了使其可读,您可以使用 ENUM
。如果您需要有关状态的更多信息,可以使用单独的 table 和 PRIMARY KEY(status)
以及有关状态的其他列。
案例二:address
“地址”体积庞大,可能有多列。 (但是,由于 WHERE
或 ORDER BY
子句很少需要“地址”的组成部分,所以很少有充分的理由以 TEXT
以外的任何形式使用它,并且嵌入换行符。
但是,“addressis usually implemented as several separate fields. In this case, a separate table is a good idea. It would have a column
id MEDIUMINT UNSIGNED AUTO_INCREMENT PRIMARY KEYand the various columns. Then, the other tables would simply refer to it with an
address_idcolumn and
JOIN` 需要时 table . 这很干净,即使许多 table 都有地址也能正常工作。
一个警告:当您需要更改某个实体的地址时,如果您已经删除了重复地址,请小心。最好总是添加一个新地址,并将 space 浪费在任何不再需要的地址上。
讨论
这两种情况(状态和访问)可能是极端情况。对于每个可能常见的列,决定哪个更有意义。正如 Bill 指出的那样,您确实需要考虑查询才能获得架构 'right'。在决定 PRIMARY KEY
以外的索引之前,您 必须 编写主要查询。 (所以,我现在不会回答你关于索引的问题。)
不要使用 4 字节 INT
来表示小的东西,主要是 immutable,并且更容易阅读:
- 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', ...)
您的“文件夹”与“文档”是一对多关系的示例。是的,它是通过在 table Folders
.
doc_id
来实现的
“多对多”需要额外的 table 来连接两个 table。
枚举
有些人会反对使用 ENUM
。在您的情况下,无法确保每个 table 使用相同的定义,例如 doc_type
。在列表 的末尾添加一个新选项 很容易,但重新排列 ENUM
.
ID
id
(或 ID
)几乎普遍保留(按照惯例)表示 table 的 PRIMARY KEY
,通常(但不一定) AUTO_INCREMENT
。请不要违反这个约定。请注意,在我上面的示例中,id
是 Addresses
table 的 PK,但在引用 table 中调用了 address_id
。您可以选择在两个table之间创建一个FOREIGN KEY
。