1

目前,我们记录了用户最近 20 次媒体浏览量,以便他们可以查看最近浏览内容的简要历史记录页面。

为此,我们将媒体 ID 插入到表中。

为了保持表格较小,目前每个用户只有 20 个项目,因此在插入行之前,我们检查他们当前有多少历史记录 ID,如果小于 20,那么我们只需插入新行,如果超过20 然后我们必须选择最后一行并将其删除,然后才能插入新行。

$historyResult = mysql_query("SELECT id FROM mediatable WHERE userId = $userId ORDER BY id ASC");

if(mysql_num_rows($historyResult) >= 20)
{
    $historyResult = mysql_query("SELECT id FROM mediatable WHERE userId = $userId ORDER BY id ASC LIMIT 1");
    $historyRow = mysql_fetch_row($historyResult);
    mysql_query("DELETE FROM mediatable WHERE id = '$historyRow[0]'");
}

mysql_query("INSERT INTO mediatable (userId, mediaId) VALUES ($userId, $mediaId))");

我现在正在将该站点转换为更现代的代码,并将使用 pdo 查询,我的问题是:

以上是解决这个问题的好方法还是我应该使用另一种方法,例如插入时的 MySQL 触发器?

4

3 回答 3

7

如果您真的对最大速度感兴趣,还有一个非常高效的选项,即不首先检查有多少行,而是在后台进行清理操作修剪它们。每当您想插入新行时,只需直接执行即可。每当您获取要显示的最新行时,请使用LIMIT 20.

垃圾收集器进程可以根据需要独立运行,查找具有超过 20 条历史记录的用户并适当地删除最旧的用户。这样,您就可以保证最近历史项目的下限(假设它们是在某个时间点创建的)以及等待修剪的旧历史记录的数量不受限制但实际上非常低。您可以根据自己的喜好决定收集频率。

另一方面,如果您追求的不是绝对性能,那么从 PHP 进行检查应该没问题——前提是您SELECT COUNT(*) FROM mediatable WHERE userId = $userId在查看已经存在多少个 id 时将其更改为执行。这样,到目前为止,修改您的保留策略也更容易。

更新:要考虑的垃圾收集策略

  1. Scheduled GC:收集定期发生,很可能按固定时间表进行。通常,这被实现为 cron 作业或计划任务,具体取决于操作系统。优点包括可靠性和使用历史数据的选项来显着降低等待修剪的项目的标准偏差。此外,清理不与(也不应该阻止)任何一个用户请求相关联;这消除了用户必须等待 GC 完成才能获得其内容的情况(通常很少见)。
  2. 概率 GC:收集是随机触发的。您的应用程序指定了一组可以触发 GC 的操作(例如,创建一个新的历史记录项),以及每当集合中的任何操作发生时触发 GC 的概率;收集可以作为处理操作的一部分发生,或者收集器可以是按需启动的单独进程。最显着的优势是不需要在应用程序外部进行设置,如果您的应用程序不打算广泛分发,这可能不那么重要。在考虑每单位时间触发动作的平均数量的同时调整 GC 概率允许您定位(尽管粗略)连续收集之间的所需间隔。
于 2012-05-29T20:20:34.353 回答
1

The following will insert a new row or reuse an existing id if a user has more than 20 rows inserted already. The query uses the oldest existing id for this user.

mysql_query("
INSERT INTO mediatable (id, userId, mediaId) 
    SELECT m.idd, d.u, d.m
    FROM 
        (SELECT " . $userId . " u, " . $mediaId . " m FROM dual) d LEFT JOIN (
                    SELECT userid u, MIN(id) idd FROM mediatable
                    WHERE 
                        userid = " . $userId . "
                    GROUP BY 
                        userid
                    HAVING COUNT(*) > 20
                ) m ON d.u = m.u
");
于 2012-05-29T20:34:41.613 回答
0

您可以做的最好的事情是,制作一个存储过程,只需将您的新数据和最大长度
最大长度传递给它,因为现在它的 20 变大了,可能需要更改,所以动态更好
触发器也很好,但预编译程序,在速度和定制方面进行比较时会更好。

于 2012-05-29T20:20:19.800 回答