使用JOIN以便数据库可以将其作为一个查询为您优化:
SELECT u.uid, COUNT(l.id)
FROM Users u -- or whatever your users table is named
LEFT JOIN logs l
ON l.uid = u.uid AND l.time + l.date > $timeNow
GROUP BY u.uid
在英语中,这告诉数据库,“给我一个用户 ID 列表以及与它们相关联的日志数量,time + date
之后在哪里$timeNow
”。这显着提高了效率,因为您一次将所有工作交给数据库,因此它可以找出获取所有信息的最佳方式,而不是一次抓取一个信息。
加入
LEFT JOIN
告诉数据库通过查找用户表和日志表相同的记录来匹配用户和日志uid
。LEFT
inLEFT JOIN
告诉数据库为用户返回一个结果(连接的左侧),即使他们没有与他们关联的任何日志(连接的右侧)。如果您不想在没有用户日志的情况下看到结果,您可以执行INNER JOIN
,这将只显示联接两边都匹配的结果(用户和至少一个日志消息)。
通过...分组
有必要按用户 ID 对结果进行分组 - 否则您只会获得与任何GROUP BY
用户关联的日志消息的总数,这可能没有帮助,因为您只能.SELECT COUNT(*) FROM logs
我使用表别名来缩短查询,因为它是我一直使用的样式,但您可以轻松地输入表的全名(logs.uid
等)。您甚至可以不包括表名而逃脱,但是当您在查询中引用存在于多个表中的列时,您的数据库会感到困惑,因此我发现始终明确说明您的列是最简单的再谈。
索引
除非您有一个非常大的数据库,否则这个新查询应该会立即完成。如果没有,请接受@charly 的建议并尝试一些索引。不幸的是,您l.time + l.date
在使用该值之前添加,我认为 MySQL 不会让您在 上创建索引l.time + l.date
,但您可以通过l.date
首先过滤(可索引)获得不错的结果:
ON l.uid = u.uid AND l.date > $timeNow AND l.time + l.date > $timeNow
这看起来很重复,但它为数据库提供了更多可使用的功能,因为它可以:
- 使用 index获取结果 where
l.date
is 。$timeNow
- 用 过滤那组(希望很小的)结果
l.time + l.date > $timeNow
。
代替:
- 对于表中的每条记录,添加
l.time + l.date
.
- 检查该结果是否在
$timeNow
PHP
要在 PHP 中执行此操作,您需要执行以下操作:
$sql = // that query above
$result = mysql_query($sql);
while($row = mysql_fetch_array($result)) {
echo "User " . $row[0] . " posted " . $row[1] . " times.";
}
或者,如果您需要以更复杂的方式使用它,请预先获取所有内容:
$counts = array();
$sql = // that query above
$result = mysql_query($sql);
while($row = mysql_fetch_array($result)) {
$counts[$row[0]] = $row[1];
}
// later
$user = 5; // some user we care about
echo "User " . $user . " posted " . $counts[$user] . " times.";
如果您以“预先获取所有内容”的方式执行此操作,您还可以通过使用INNER JOIN
查询版本进行一些优化,并且知道任何不在其中的用户$counts
的计数为 0。
对不起,如果我的语法错误,但我认为这说明了这个想法。
安全说明
一个小切线:看起来您将变量直接放入查询中,这通常是一个坏主意。有许多非常复杂的解决方案,但最简单的方法是只使用参数化查询,并且永远不要将变量直接放入 SQL 中。