Php 如何在三表系统中插入标签

Php 如何在三表系统中插入标签,php,mysql,sql,insert,database-performance,Php,Mysql,Sql,Insert,Database Performance,尽管像Joomla这样的一些主要系统将标记作为逗号分隔的文本存储在主文章数据库中,但还是首选由三个表组成的规范化系统,即文章、标记和标记关系(如Wordpress等其他系统所使用的)。有很多关于结构和阅读的讨论和问题;但是我找不到最好的INSERT命令,因为我们需要插入到三个表中。如何通过一次SQL运行快速运行此过程?或者我们需要先插入文章,然后插入每个标签,最后写入关系 另一个问题是关于标签的唯一性。这个系统的主要优点是我们只需要存储每个术语一次(然后连接到相应的文章)。使用mysql UNI

尽管像Joomla这样的一些主要系统将标记作为逗号分隔的文本存储在主文章数据库中,但还是首选由三个表组成的规范化系统,即文章、标记和标记关系(如Wordpress等其他系统所使用的)。有很多关于结构和阅读的讨论和问题;但是我找不到最好的INSERT命令,因为我们需要插入到三个表中。如何通过一次SQL运行快速运行此过程?或者我们需要先插入文章,然后插入每个标签,最后写入关系

另一个问题是关于标签的唯一性。这个系统的主要优点是我们只需要存储每个术语一次(然后连接到相应的文章)。使用mysql UNIQUE以避免重复是否可行?或者(正如我在某处读到的)我们需要将整个标签列表作为一个数组来读取,以找到任何重复项来捕获标签ID并避免存储术语

将整个过程分为三个单独的步骤:

  • 插入文章
  • 插入具有唯一性但不考虑其关系的标记
  • 查找每个标记ID并与项目ID建立关系

  • 我说得对吗?我问这个问题的原因是,我看到人们将标签作为数组捕获并进行比较。对我来说,它非常慢,并且会降低性能,尤其是对于更新。

    您不能在一条语句中插入到3个表中,但可以在一个事务中运行3条insert语句


    我不认为将标记列声明为唯一列有任何问题,因为您希望避免重复。在将标记插入到表中之前,您始终可以检查标记是否存在,最好是检查标记。

    如果通过发出单个查询来运行每个插入,则没有“解决方法”,甚至不可能存在一个。因此,3个表有3个插入

    如果您需要唯一的标记,那么是的-最好使用唯一约束来避免重复


    简单的
    INSERT IGNORE
    MySQL功能可以帮助您在插入之前避免记录是否存在。

    您一次只能插入一个表

    一种解决方案是使用触发器,另一种是使用事务。
    第一个可以用于任何引擎,后者需要InnoDB或类似的引擎

    确保在字段
    标记.name
    上放置一个
    唯一的
    索引

    1-使用交易

    START TRANSACTION;
    
    INSERT IGNORE INTO tag (name) VALUES ('$example1', '$example2');
    INSERT INTO article (title, body) VALUES ('$title','$body');
    SET @article_id = LAST_INSERT_ID();
    INSERT INTO tag_link (tag_id, article_id) 
      SELECT t.id, @article_id FROM tag t WHERE t.name IN ('$example1','$example2');
    
    COMMIT;
    
    2-在黑洞表上使用触发器

    创建一个具有以下字段的
    blackhole
    类型的表

    title: varchar(255)
    body: text
    tag1: varchar(50) DEFAULT NULL
    tag2: varchar(50) DEFAULT NULL
    ...
    add as many tags as you want.
    
    在插入触发器后向黑洞表添加一个
    ,为您进行实际存储

    DELIMITER $$
    
    CREATE TRIGGER ai_bh_newacticle_each AFTER INSERT ON bh_newacticle FOR EACH ROW
    BEGIN
      INSERT IGNORE INTO tag (name) VALUES (new.tag1, new.tag2,...,new.tag25);
      INSERT INTO article (title, body) VALUES (new.title,new.body);
      SET @article_id = LAST_INSERT_ID();
      INSERT INTO tag_link (tag_id, article_id) 
        SELECT t.id, @article_id FROM tag t 
        WHERE t.name IN (new.tag1, new.tag2,...,new.tag25);
    END$$
    
    DELIMITER ;
    DELIMITER $$
    现在,您可以在一条语句中插入带有标记的文章:

    INSERT INTO bh_newarticle (title, body, tag1, tag2, tag3) 
      VALUES ('$title','$body','$tag1','$tag2','$tag3');
    
    回到你的问题

    我说得对吗?我问这个问题的原因是,我看到人们将标签作为数组捕获并进行比较。对我来说,这是非常缓慢的,并扼杀了性能,尤其是更新

    标签只有在数量有限的情况下才有用。如果在
    tag.name
    上放置一个(唯一)索引,即使有10.000个标记,查找标记的速度也会非常快。这是因为你正在寻找一个精确的匹配。如果您真的很忙,您可以在
    name
    字段上使用
    hash index
    将标记表设置为
    memory
    表。
    不过,我怀疑您是否需要担心标记查找的缓慢性

    只是确保你不允许每篇文章有太多的标签。5似乎是个好的开始。10个太多了

    链接


    根据DBMS的功能,有一些可能性,例如: 存储过程,而不是触发器,可以是任何其他方法,使插入一个sql语句成为可能,但我认为这不值得,因为即使在一个事务中插入所有3个表,也不那么重要。。。这是不错的,如果文章保存,但标签未能保存。。。但是,如果需要,存储过程是这个任务的最佳选择,因为它允许复杂的逻辑,并且您还可以在程序中编写子程序来执行所有sql,并在需要时在一行中调用它


    您可以在标记字段上的标记表和字段上的rel表(article_id,tag)上创建唯一索引

    如果文章保存了,但是标签保存失败,这也不错
    。毫无意义为什么?作者总是可以在文章中添加标签(如果文章被保留…),标签用于查找文章。如果标签可能丢失,那么很难找到文章。非常糟糕的设计。一个应用程序应该可以正常工作,它不需要重复检查,也不需要文章作者的手。没有人说应该丢失一些东西,但使用事务意味着,如果无法在标记表中写入数据,那么文章的内容也不会写入文章表中。。。在金融或任何其他业务中,它有助于保持(fin)平衡和数据一致性,但这篇文章比它的标签更有价值,应该保存,即使保存标签是不可能的。当然,如果标签丢失了是非常糟糕的,但是如果标签与文章一起丢失则更糟糕