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

Fan*_*ang 3 mysql tagging database-design database-schema

我对标签数据库模式的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. 完成(给用户一个好的,等等)

这意味着我们最终会在tagmap中为每个项目的每个标记添加一个条目.这似乎是正确的,但我不禁想到有更好的方法来做到这一点,而不是那里有大量的条目......

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

  1. 使用item_id获取标签并插入可编辑字段
  2. 用户进行更改.提交时:
  3. 从tagmap中删除行,其中item_id与正在编辑的行匹配
  4. 与上面列出的过程相同的过程

我对那里的第3点有点不满意.有没有办法让我检查是否有任何标签被删除,所以我可以有选择地删除标签而不是删除和重新添加标签?并且只是为了确定:删除tagmap行时,相关项目不会被删除,因为它指向一个外键而不是一个,对吧?

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

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

提前致谢!

Bra*_*vic 13

首先,"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');
Run Code Online (Sandbox Code Playgroud)

IGNORE允许即使项目已经连接到某些标记这一成功.

这假定所有必需的标签已经存在tags.假设tag.tag_id是自动递增,您可以执行以下操作以确保它们是:

INSERT IGNORE INTO tags (tag_text) VALUES ('tag1'), ('tag2'), ('tag3');
Run Code Online (Sandbox Code Playgroud)

这意味着我们最终会在tagmap中为每个项目的每个标记添加一个条目.这似乎是正确的,但我不禁想到有更好的方法来做到这一点,然后在那里结束了大量的条目......

没有魔力.如果"项目连接到特定标签"是您要记录的知识,那么它必须在数据库中具有某种物理表示.

至于编辑标签......

你的意思是重新标记项目(不是自己修改标签)?

要删除列表中没有的所有标记,请执行以下操作:

DELETE FROM tagmap
WHERE
    item_id = 1
    AND tag_id NOT IN (
        SELECT tag_id FROM tags
        WHERE tag_text IN ('tag1', 'tag3')
    );
Run Code Online (Sandbox Code Playgroud)

这将使项目与除"tag1"和"tag3"之外的所有标记断开连接.执行上面的INSERT并依次执行此DELETE以"覆盖"添加和删除标记.

您可以在SQL Fiddle中使用所有这些.

并且只是为了确定:删除tagmap行时,相关项目不会被删除,因为它指向一个外键而不是一个,对吧?

正确.FK的子端点不会触发参照操作(例如ON DELETE CASCADE),只有父级才会触发.

顺便说一句,您正在使用此架构,因为您需要tags(旁边tag_text)中的其他字段,对吧?如果你这样做,不要因为所有连接都消失而丢失这些额外的数据.

但是如果您只是想要tag_text,那么您将使用更简单的架构,删除所有连接与删除标签本身相同:

在此输入图像描述

这不仅可以简化SQL,还可以提供更好的群集.

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

另外,我可能想跟踪标签... cron作业的次数......

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

在任何情况下,衡量实际数据量!