加速基于多对多更新的文本

时间:2015-08-10 17:44:56

标签: php mysql tags many-to-many crud

TL; DR;

当ids未知时,是否有更快的方式更新m:m记录逐个循环。

这是关于使用标签。

在前端,我有表单使用基于文本的输入来列出和更新标签。

提交表单时,用户记录需要通过删除和创建m:m表中的记录来更新标记

有多种标记类型,因此有多个标记输入字段,但都存储在同一个表中。

因为当前系统使用标签作为字符串,一旦表单将输入数据传递回服务器,它就是一个CSV字符串。

计划(计划,因为我从存储作为字符串更新)是

  • 加入所有代码$tags = implode(',', array_merge($tagset1, $tagset2));
  • 获取单个代码$update_tags = explode(',',$tags);
  • 在m:m user_tag table
  • 中删除用户的所有标签
  • 循环$update_tags作为$tag_name
    • $tag_name
    • 中找到tag_id
    • 将记录添加到m:m user_tag表中,用于user_id和tag_id组合

过去我发现了删除发生的问题,但是一些未处理的错误导致更新无法通过。我怀疑通过实施回滚可以减轻这种情况。

虽然双方用于更新的标签数量相当低(用户将少于15个,总共少于1000个标签)但我担心这个循环方面,因为过去的经验非常好指示循环中的sql是一个很好的避免。

1 个答案:

答案 0 :(得分:0)

这就是我最终做的......

它与我的意图有点不同。

我将字符串分解并与视图结果(作为数组)进行比较并执行两个array_diff操作,一个用于查找删除操作,另一个用于查找插入操作。

每种操作类型都有一个查询,查找用户标签,插入用户标签,删除用户标签。

唯一的重复是根据标记名称查找标记ID的查询,在这种情况下它无论如何都不会循环。

public function update_tags($user_id, $tags)
{
    // convert tags string to array
    $update_tags = explode(',',$tags);

    // find user's tags
    $user_tag_view_reslt = $user_tag_view->find(array("user_id = ?", $user_id));

    // reduce to array with tag names only
    $user_tag_view_reslt = array_column( $user_tag_view_reslt, 'tag_name');

    $remove_tags = array_diff($user_tag_view_reslt, $update_tags);
    $insert_tags = array_diff($update_tags, $user_tag_view_reslt);

    $this->remove_user_tags($user_id, $remove_tags);
    $this->insert_user_tags($user_id, $insert_tags);
}

public function remove_user_tags($user_id, $tags_array)
{
    $tags_string = "'".implode("','",$tags_array)."'";
    $tag_model = new \Model\Tag();

    $rows = $db->exec("SELECT tag_id FROM tag WHERE tag_name in($tags_string) ");
    $delete_tag_ids = implode(',',array_column($rows,'tag_id'));

    // check if there are any rows to insert before doing so
    if($delete_tag_ids != ''){
        $exec = $db->exec("DELETE FROM `user_tag` WHERE user_id = $user_id AND tag_id in ($delete_tag_ids);");
    }
}

public function insert_user_tags($user_id, $tags_array)
{
    $tags_string = "'".implode("','",$tags_array)."'";
    $tag_model = new \Model\Tag();
    $rows = $db->exec("SELECT tag_id FROM tag WHERE tag_name in($tags_string) ");
    $insert_tag_ids = implode(',',array_column($rows,'tag_id'));

    $sql_vals = array();
    foreach($rows as $row){
        array_push($sql_vals,"($user_id, ".$row['tag_id']." )");
    }
    $sql_vals_str = implode($sql_vals,",");

    // check if there are any rows to insert before doing so
    if($insert_tag_ids != ''){
        $exec = $db->exec("INSERT INTO `user_tag` (user_id, tag_id) VALUES $sql_vals_str;");
    }
}

需要PHP 5.5或更高版本(由于array_column),它也无法调整和适应未显示代码的模型