我正在构建一个业务目录,用户可以在其中为其业务创建列表。目录的结构如下:
目前的数据结构如下:
category tag
============ ===========
id id
name name
category_id (FK)
listing listing_category listing_category_tag
============ ================ ====================
id id listing_category_id (FK)
name listing_id (FK) tag_id (FK)
etc category_id (FK)
随着目录的建立,我将不可避免地想要添加新的类别和标签,现有的可能必须归档。这可能意味着需要更新一些列表以引用新创建的类别和标签。
此数据结构是否有效设置以处理此类情况?我想避免列表中的标签与当前类别分配不匹配的情况。
答案 0 :(得分:1)
为了保持数据库级别的一致性,我建议在联结表中使用自然复合主键而不是代理标识符:
category tag
============ ================
id (PK) name (PK)(UC)
name (UC) category_id (PK)(FK)
listing listing_category listing_category_tag
============ ================ ====================
id (PK) category_id(FK)(PK) listing_category.PK (FK)
name (UC) listing_id (FK)(PK) tag.PK (FK)
etc
我们最终会得到这样的结论:
listing_category_tag
====================
listing_category_category_id (FK)
listing_category_listing_id(FK)
tag_name(FK)
tag_category_id(FK)
现在有检查约束,如
check_constraint_1 = {listing_category_category_id = tag_category_id}
会阻止不一致
答案 1 :(得分:1)
您提出的设计是合理的。我会在这里列出一些灰色区域,而不是挑战你的方法以激发思想:
listing_category引用类别。标签也引用类别。 listing_category_tag引用标记和列表类别,因此如果未维护引用完整性,则可以使用listing_category_tag引用与标记类别中的不同类别相关联的列表。我认为这表明设计不在Boyce-Codd Normal Form中,但可能是第3次正常?
正如您所描述的那样,随着时间推移更改类别和标签的可能性,这可能会成为一堆参考依赖项。我知道这在理论上听起来很棒,但在实际操作中,当设计允许引用不一致时,小错误很容易复合。 (是的,约束,但在实际操作中,这种情况很容易摆脱困境。)
您是否考虑过更简单,更规范的非规范化方法?这变得越来越普遍,并且在一些非常大且成功的站点上被广泛使用。例如:
listing listing_category_tag
========== ====================
id listing_id
name category_name
etc. tag_name
在listing_category_tag上放置一个复合索引(category_name,tag_name)。如果您需要一个类别列表,只需select distinct(category_name)
,当您想要一个类别的唯一标记列表时,select distinct(tag_name) where category=?
您可能会惊讶地发现,即使是数百万个列表,它的表现也会有多好,以及实现和维护错误的程度会更简单,也更不容易出错。
我希望这有用!
答案 2 :(得分:0)
您的数据结构非常适合您尝试解决的挑战。
这可能意味着需要更新一些列表以引用新创建的类别和标签......
我希望避免列表中的标签与当前类别分配不匹配的情况。
这可以通过几种不同的方式实现。
如果您选择第一种方法,则无需在您已经拥有的模型上进行任何操作。当您更新或插入新的列表/标签/类别时,应用程序代码必须确保它们有效。
如果选择第二种方法,则将listing_category_tag
中的外键更改为复合外键,并指定适当的约束。
listing_category_tag
====================
listing_category_id (FK: listing_category)
tag_id (FK: tag)
category_id (FK: tag)
The MySQL Documentation有很好的例子,说明如何使用约束。
答案 3 :(得分:0)
我认为您的设计在强制执行包含约束时,所有已分配的标记必须与列表具有相同的类别,这是非常复杂的。更简单,更自然的设计也强制执行包含约束,如下所示
category tag
============ ===========
id category_id (FK)
name name
PK( category_id, name)
listing listing_category listing_tag
============ ================ ====================
id listing_id (FK) listing_id (FK)
name category_id (FK) category_id (FK)
etc tag_name (FK)