标记系统:Toxi解决方案问题

时间:2012-05-08 20:43:02

标签: mysql database-design database-schema tagging

我对标签数据库模式的Toxi解决方案感到不满。我正在开发一个用户可以提交项目的系统,这些项目可以有与之关联的标签。在阅读了标签之后,我找到了最适合我需求的Toxi解决方案。但是,我不能完全确定我是否计划好这个,所以我希望你对此有所了解。

我将有三个数据库。
items包含item_id和其他人
tagmap使用item_idtag_id作为外键
tags包含tag_idtag_text

添加新项目时,我是否正确地假设将标记添加到数据库的过程如下?

  1. 将提交的标签分类到数组
  2. 对于数组中的每个标记:
    1. 从标签中获取tag_id,其中tag_text与当前标签匹配
    2. 如果返回0行:
      1. 将标签添加到标签表
      2. 获取tag_id
    3. 将item_id和tag_id添加到tagmap
  3. 完成(给用户一个好的,等等)
  4. 这意味着我们最终会在tagmap中为每个项目的每个标记添加一个条目。这似乎是正确的,但我不禁认为有更好的方法来做到这一点,而不是在那里结束大量的条目......

    至于编辑标签,我已经想到了以下过程,但我认为还有一种更好的方法,我还没有找到。

    1. 使用item_id获取标签并插入可编辑字段
    2. 用户进行更改。提交:
    3. 从tagmap中删除行,其中item_id与正在编辑的行匹配
    4. 与上面列出的过程相同的过程
    5. 我对那里的第3点有点不满意。有没有办法让我检查是否有任何标签被删除,所以我可以有选择地删除标签而不是删除和重新添加标签? 并且只是为了确定:当删除tagmap行时,相关的项目不会被删除,因为它指向一个外键而不是一个,对吗?

      此外,我可能想要跟踪标记的使用次数,但我不想运行查询来计算每次需要显示的标记。我正在考虑让cron作业每小时或每两小时计算一次tagmap中每个tag_id的实例数,然后更新tags表中的tag_use值。这是一种正确的方法吗,还是有更好的方法?

      回顾过去,这是相当多的文字。 Welp,比缺少信息更详细,而是提出太多问题并学习很多新事物,而不是要求太少。 很有可能我今天花了太多时间研究这个问题,明天这一切都会更有意义。

      提前致谢!

1 个答案:

答案 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,那么您将使用更简单的架构,删除所有连接与删除标签本身相同:

enter image description here

这不仅可以简化SQL,还可以提供更好的clustering

乍一看,“toxi”可能看起来像是在节省空间,但实际上可能并非如此,因为它需要额外的表和索引(而且标签往往很短)。

  

另外,我可能想跟踪标签... cron job ...

的次数

在决定做这样的事情之前测量。上面提到的我的SQL小提琴在tagmap PK中使用了非常谨慎的字段顺序,因此数据以对这种计数非常友好的方式聚类(记住:InnoDB tables are clustered)。在此成为问题之前,您必须拥有真正大量的项目(或需要异常高的性能)。

无论如何,衡量关于实际数据量!