【问题标题】:MySQL Processing votes for a like/dislike system via AJAX and PHPMySQL 处理通过 AJAX 和 PHP 为喜欢/不喜欢系统投票
【发布时间】:2015-09-15 08:07:06
【问题描述】:

我有一个网站,其中包含对其内容的投票系统。因此,我设置了一个名为votes 的 MySQL 表,其中包含 uidpidvalue 的列,对应于用户投票的 UUID、帖子的基于文本的 ID 和布尔值投票的价值(01 表示不喜欢和喜欢)。

我见过几个类似的问题,尽管似乎没有一个直接涉及在 PHP 和 MySQL 数据库之间的通信中插入和操纵投票。大多数似乎是指database structureSELECTing values。我找不到的似乎都模仿了我最终想要的系统。

与之交互的数据库和 PHP 工作正常 - 我设置了某些页面,这些页面生成 JSON,其中包含该帖子的每种类型的投票数量和给定用户的个人投票。我遇到的问题是优化用户输入投票的过程 - 我在投票时寻找的“规则”如下:

  • 如果输入的确切投票已经存在(即给定uidpidvalue 都作为相同的记录存在),则从表中删除该投票;
  • 如果当前没有对此帖子和此用户的投票,请在表格中添加所有三个值的投票;
  • 如果此用户对此帖子投了票,但投票结果相反(不喜欢而不是喜欢,反之亦然),请更新记录以使投票匹配。

页面通过会话变量接收$currentUid,并通过GET 参数接收$cid$_GET["v"](显然)。

我已经能够通过在两个 MySQL 调用中使用 PDO 在 PHP 中产生这种行为(假设 $con 是一个通用 PDO 对象):

$test = $con->prepare("SELECT * FROM `votes` WHERE uid=UNHEX(:uid) AND pid=:pid AND value=:value");
$test->bindValue(":uid", $currentUid);
$test->bindValue(":pid", $pid, PDO::PARAM_INT);
$test->bindValue(":value", $_GET["v"], PDO::PARAM_BOOL);
$test->execute();

if($test->rowCount() > 0) {
    $query = $con->prepare("DELETE FROM `votes` WHERE uid=UNHEX(:uid) AND pid=:pid AND value=:value LIMIT 1");
    $query->bindValue(":uid", $currentUid);
    $query->bindValue(":pid", $pid, PDO::PARAM_INT);
    $query->bindValue(":value", $_GET["v"], PDO::PARAM_BOOL);
    $query->execute();
} else {
    $query = $con->prepare("INSERT INTO `votes` (uid, pid, value) VALUES (UNHEX(:uid), :pid, :value) ON DUPLICATE KEY UPDATE value = :value");
    $query->bindValue(":uid", $currentUid);
    $query->bindValue(":pid", $pid, PDO::PARAM_INT);
    $query->bindValue(":value", $_GET["v"], PDO::PARAM_BOOL);
    $query->execute();
}

有没有什么方法可以通过一个更大的 MySQL 调用来达到同样的效果,它会以任何方式影响系统的性能吗?我过去发现,使用较长的 MySQL 语句可能比简单地使用 PHP 和 MySQL 的混合解决方案花费更长的时间。可以假设系统会经常处理投票,所以性能在这里很重要。

目前这个过程大约需要 0.05 秒(通过简单的microtime() 基准测试),考虑到多个并发用户,这肯定会加起来。

感谢您的帮助!请注意,我不是 SQL 语法专家,我刚刚学会了如何执行 INNER JOIN - 这就是我决定在这里发帖的原因,好像有一些 MySQL 函数可以做到这一点很难找到它。

【问题讨论】:

    标签: php mysql database pdo


    【解决方案1】:

    似乎不太可能在一个 mysql 调用中做同样的事情。

    作为第一步,删除 SELECT 查询,除非您绝对需要它以供以后使用。您的 ON DUPLICATE KEY 声明会为您执行此操作。

    但是,DELETE 是必要的。没有 ON DUPLICATE KEY DELETE 语法。

    但是,您可以编写一个在 AFTER INSERT 后工作的 TRIGGER 并删除重复项(如果有)。这是一种粗略的方法,但它会减轻 PHP 的负担。如果您绝对坚持在 SINGLE 查询中完成任务,请执行此操作

    【讨论】:

      【解决方案2】:

      如果您将表 votes 上的 UNIQUE 约束设置为 (uid, pid),那么您只需要 ON DUPLICATE KEY UPDATE...如果您将考虑使用三元 ENUM -- +1, 0, -1 -- 在value 中适当地表示“喜欢”、“没有意见”和“不喜欢”。

      如果给定的(uid, pid) 组合不存在投票,INSERT ... ON DUPLICATE KEY UPDATE 将插入提供的值。如果存在投票并且用户希望撤回反对票(从 -1 到 0),撤回反对票(1 到 0)或应用反对票或反对票(0 到 1 或 -1) , INSERT ... ON DUPLICATE KEY UPDATE 将改为更新记录。

      使用这种方法,删除投票的唯一原因是级联操作,例如删除帖子或用户记录。我敢打赌,您可能有一些应用程序代码可以将 Boolean TRUE 转换为 Integer +1 并将 Boolean FALSE 转换为 -1。作为奖励,记录 0 票还提供有关该用户之前是否对该帖子进行过投票的信息,即使他们后来撤回了赞成或反对的投票。

      作为最后的考虑,您应该将您的投票更改操作包装在一个事务中,并对您想要 UPDATE 的行进行过度限定,以防止与用户的 next 操作发生冲突,这可能会被处理出现故障因为...嗯,互联网。

      【讨论】:

      • 是否值得在数据库中增加空间来实现这一点(用于额外的记录),而且它会大大提高性能吗?我不想记录用户过去是否投票过。
      • MySQL 使用ENUM 非常高效,因此不会有太大的大小或性能损失。考虑一个清理 0 值投票记录的真空任务:DELETE FROM votes WHERE created_on > yesterday AND value = 0
      猜你喜欢
      • 2011-09-29
      • 2015-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-26
      • 2018-05-27
      相关资源
      最近更新 更多