我是一名软件开发人员。我喜欢编码,但我讨厌数据库...目前,我正在创建一个网站,允许用户将实体标记为 like (如FB中),标签它和评论。
我被困在数据库表设计上以处理此功能。解决方案是微不足道的,如果我们只能为一种类型的东西(例如照片)做到这一点。但是我需要为5种不同的东西启用它(现在,但我也假设随着整个服务的增长,这个数字会增长)。
我在这里发现了一些类似的问题,但没有一个问题得到满意的答案,所以我再次提出这个问题。
问题是,如何正确地有效地和弹性地设计数据库,以便它可以存储不同表的注释,< em>喜欢用于不同的表和标签。一些设计模式作为答案将是最好的;)
详细说明:
我有表 User
包含一些用户数据,还有3个表:Photo
包含照片,{{ 1}}与文章,Articles
与地方。我想启用任何已登录的用户:
评论这3个表中的任何一个
将其中任何一个标记为喜欢
使用某些标记
我还想计算每个元素的喜欢次数以及使用特定标记的次数。
1 st 方法:
a)对于标签,我将创建一个表 Places
,然后我将创建多对多关系表格:Tag [TagId, tagName, tagCounter]
,Photo_has_tags
,Place_has_tag
。
b)同样重要的评论。
c)我将创建一个表 Article_has_tag
,LikedPhotos [idUser, idPhoto]
,LikedArticles[idUser, idArticle]
。 赞的数量将由查询计算(我认为这是不好的)。而且......
我真的不喜欢这个设计的最后一部分,它对我来说很难闻;)
2 nd 方法:
我将创建一个表LikedPlace [idUser, idPlace]
,该表将由管理员(我)填充,其中表的名称可以喜欢,评论或标记。然后我将创建表:
a)ElementType [idType, TypeName == some table name]
和评论和标签相同,每个都有适当的列。现在,当我想拍照时,我会插入:
LikedElement [idLike, idUser, idElementType, idLikedElement]
和地方:
typeId = SELECT id FROM ElementType WHERE TypeName == 'Photo'
INSERT (user id, typeId, photoId)
依旧......我认为第二种方法更好,但我也觉得这个设计中也缺少某些东西......
最后,我也想知道哪个最好的地方存放计数器元素被喜欢多少次。我只能想到两种方式:
typeId = SELECT id FROM ElementType WHERE TypeName == 'Place'
INSERT (user id, typeId, placeId)
)表我希望我现在对这个问题的解释更加彻底。
答案 0 :(得分:162)
最具扩展性的解决方案是只拥有一个&#34; base&#34;表格(连接到&#34;喜欢&#34;,标签和评论),以及&#34;继承&#34;所有其他表格。添加一种新的实体只需添加一个新的&#34;继承的&#34; table - 然后它会自动插入整个like / tag / comment机器。
实体关系术语是&#34;类别&#34; (参见ERwin Methods Guide,部分:&#34;子类型关系&#34;)。类别符号为:
假设用户可以喜欢多个实体,同一个标签可以用于多个实体,但注释是特定于实体的,您的模型可能如下所示:
除非您有非常严格的性能要求,否则第三种方法可能是最好的(意味着物理表与上图中的实体1:1匹配)。
答案 1 :(得分:19)
既然你“讨厌”数据库,你为什么要尝试实现一个?相反,向喜欢和呼吸这些东西的人寻求帮助。
否则,学会爱你的数据库。精心设计的数据库简化了编程,设计网站并平滑其持续运营。即使是经验丰富的d / b设计师也不会有完整和完美的远见:随着使用模式的出现或需求的变化,将需要一些架构变化。
如果这是一个单人项目,请使用存储过程将数据库接口编程为简单操作:add_user,update_user,add_comment,add_like,upload_photo,list_comments等。不要将模式嵌入到一行代码中。通过这种方式,可以在不影响任何代码的情况下更改数据库模式:只有存储过程才能了解模式。
您可能需要多次重构架构。这个是正常的。不要担心第一次完美。只需使其功能足以原型化初始设计。如果您有足够的时间,请使用它,然后删除架构并再次执行。第二次总是更好。
答案 2 :(得分:18)
这是一个大致的想法 请不要太注意字段名称样式,但更多关注关系和结构
此伪代码将获取ID为5的照片的所有评论
SELECT * FROM actions
WHERE actions.id_Stuff = 5
AND actions.typeStuff =“photo”
AND actions.typeAction =“comment”
此伪代码将获得喜欢ID为5的照片的所有喜欢或用户
(你可以使用count()来获得喜欢的数量)
SELECT * FROM actions
WHERE actions.id_Stuff = 5
AND actions.typeStuff="photo"
AND actions.typeAction = "like"
答案 3 :(得分:0)
需要几张桌子。他们之间有很多关系。
答案 4 :(得分:0)
查看您将需要的访问模式。他们中的任何一个似乎在我的一个设计选择或另一个设计选择中变得特别困难或低效吗?
如果不喜欢需要较少表格的那个
在这种情况下:
我认为你的“歧视”方法,选项2,在某些情况下会产生更简单的查询,而在其他情况下看起来并不差,所以我会选择它。
答案 5 :(得分:0)
绝对采用第二种方法,你有一个表并存储每一行的元素类型,它会给你更多的灵活性。基本上,当逻辑上可以用更少的表完成某些事情时,使用更少的表几乎总是更好。我现在想到的关于你的特定情况的一个优点,考虑你想要删除某个用户的所有喜欢的元素,你需要为你的第一种方法为每种元素类型发出一个查询,但是使用第二种方法可以完成只有一个查询或考虑何时想要添加新的元素类型,第一种方法涉及为每种新类型创建一个新表,但使用第二种方法则不应该做任何事情......
答案 6 :(得分:-1)
考虑使用每个实体的表格来评论等。更多表格 - 更好的分片和缩放。对于我所知道的所有框架,控制许多类似的表并不是一个问题。
有一天,您需要优化此类结构的读取。您可以轻松地在基础表上创建agragating表,并在写入时丢失一点。
有一天,一本带字典的大表可能会变得无法控制。