我对标签数据库模式的Toxi解决方案感到不满。我正在开发一个用户可以提交项目的系统,这些项目可以有与之关联的标签。在阅读了标签之后,我找到了最适合我需求的Toxi解决方案。但是,我不能完全确定我是否计划好这个,所以我希望你对此有所了解。
我将有三个数据库。
items
包含item_id
和其他人
tagmap
使用item_id
和tag_id
作为外键
tags
包含tag_id
和tag_text
添加新项目时,我是否正确地假设将标记添加到数据库的过程如下?
这意味着我们最终会在tagmap中为每个项目的每个标记添加一个条目。这似乎是正确的,但我不禁认为有更好的方法来做到这一点,而不是在那里结束大量的条目......
至于编辑标签,我已经想到了以下过程,但我认为还有一种更好的方法,我还没有找到。
我对那里的第3点有点不满意。有没有办法让我检查是否有任何标签被删除,所以我可以有选择地删除标签而不是删除和重新添加标签? 并且只是为了确定:当删除tagmap行时,相关的项目不会被删除,因为它指向一个外键而不是一个,对吗?
此外,我可能想要跟踪标记的使用次数,但我不想运行查询来计算每次需要显示的标记。我正在考虑让cron作业每小时或每两小时计算一次tagmap中每个tag_id的实例数,然后更新tags表中的tag_use值。这是一种正确的方法吗,还是有更好的方法?
回顾过去,这是相当多的文字。 Welp,比缺少信息更详细,而是提出太多问题并学习很多新事物,而不是要求太少。 很有可能我今天花了太多时间研究这个问题,明天这一切都会更有意义。
提前致谢!
答案 0 :(得分:12)
首先,“toxi”不是一个标准术语。始终定义您的条款!或者至少提供相关链接。
现在问题本身......
我将有三个数据库。
不,你将有3张桌子。
添加新项目时......
您几乎都在正确的轨道上,除了您可以使用SQL的基于集合的特性来“合并”其中的许多步骤。例如,使用标签标记项目1:'tag1','tag2'和'tag3'可以像这样完成......
INSERT IGNORE INTO tagmap (item_id, tag_id)
SELECT 1, tag_id FROM tags WHERE tag_text IN ('tag1', 'tag2', 'tag3');
IGNORE
即使项已经连接到某些标签,也可以成功。
这假设所有必需的标签都已在tags
中。假设tag.tag_id
是自动递增的,您可以执行以下操作以确保它们是:
INSERT IGNORE INTO tags (tag_text) VALUES ('tag1'), ('tag2'), ('tag3');
这意味着我们最终会在tagmap中为每个项目的每个标记添加一个条目。这似乎是正确的,但我不禁想到有更好的方法来做到这一点,然后在那里结束了大量的条目......
没有魔力。如果“项目连接到特定标签”是您要记录的知识,那么 将在数据库中具有某种物理表示。
至于编辑标签......
你的意思是重新标记项目(不自行修改标签)?
要删除列表中没有的所有标记,请执行以下操作:
DELETE FROM tagmap
WHERE
item_id = 1
AND tag_id NOT IN (
SELECT tag_id FROM tags
WHERE tag_text IN ('tag1', 'tag3')
);
这会将项目与除“tag1”和“tag3”之外的所有标记断开连接。执行上面的INSERT并依次执行此DELETE以“覆盖”添加和删除标记。
您可以在SQL Fiddle中播放所有这些内容。
并且只是为了确定:删除tagmap行时,相关项目不会被删除,因为它指向外键而不是一个,对吧?
正确。 FK的子端点不会触发引用操作(例如ON DELETE CASCADE),只有父级才会触发。
顺便说一下,您正在使用此架构,因为您需要tags
中的其他字段(tag_text
旁边),对吧?如果你这样做,不要因为所有连接都消失而丢失这些额外的数据。
但是如果您只是想要tag_text
,那么您将使用更简单的架构,删除所有连接与删除标签本身相同:
这不仅可以简化SQL,还可以提供更好的clustering。
乍一看,“toxi”可能看起来像是在节省空间,但实际上可能并非如此,因为它需要额外的表和索引(而且标签往往很短)。
另外,我可能想跟踪标签... cron job ...
的次数
在决定做这样的事情之前测量。上面提到的我的SQL小提琴在tagmap
PK中使用了非常谨慎的字段顺序,因此数据以对这种计数非常友好的方式聚类(记住:InnoDB tables are clustered)。在此成为问题之前,您必须拥有真正大量的项目(或需要异常高的性能)。
无论如何,衡量关于实际数据量!