我正在研究页面点击计数器。页面所有者将在页面上放置一个小计数器图像,其中包含指向 Web 服务器中我的脚本的链接;当有人在浏览器中打开页面时,我的脚本将被调用并生成命中数的图像以发送回浏览器。
从 $_SERVER['HTTP_REFERER'] 我获取页面 URL,以便识别页面 ID:$page_id,并从 $_SERVER[' REMOTE_ADDR'] — 查看者主机的 IP:$ip,因为我只计算唯一的 IP。这些数据收集在表Hits(page_id, ip)中。
为了计算之前的点击次数,我计算了给定页面存储的 IP 数量:
$res1 = mysqli_query($DB, "SELECT ip FROM Hits WHERE page_id='$page_id'");
$number_of_hits = mysqli_num_rows($res1);
现在我需要测试新到达的IP是否不在旧IP中列出,否则我会丢弃它并且不会增加计数器。我可以对查询已找到的行运行循环,或者发出另一个查询:
$res2 = mysqli_query($DB, "SELECT ip FROM Hits WHERE page_id='$page_id' AND ip='$ip'");
$number_of_new_hit_occasions = mysqli_num_rows($res2);
if($number_of_new_hit_occasions == 0) ++$number_of_hits;
但第二个查询本质上是多余的,并且与第一个查询一样消耗资源;仅搜索第一个查询中获得的小结果比在第二个查询中搜索整个表要高效得多。
我希望我可以将第一个查询存储在名为 IPs_for_given_page 的内存中的虚拟表中(可能以某种方式在 $res1 中引用),并减少第二个查询查询到
$res2 = mysqli_query($DB, "SELECT ip FROM IPs_for_given_page WHERE ip='$ip'");
$number_of_new_hit_occasions = mysqli_num_rows($res2);
有什么可能吗?
最佳答案
正如您提到的那样,无法缓存结果。但是有一种更有效的方法来完成您想要做的事情。
要计算行数,请使用此类查询并检索单行结果集。这比计算结果集中的行数要快得多。
SELECT COUNT(*) FROM Hits WHERE page_id=<<whatever>>
您可以通过执行以下两项操作来自动删除 IP 号码的重复数据:
首先,在(page_id,ip)
上创建复合唯一索引。
其次,使用此SQL语句插入命中行。
INSERT IGNORE INTO Hits (page_id, ip) VALUES (<<whatever>>, <<whatever>>)
唯一索引与IGNORE
子句相结合,可以防止MySQL接受同一IP地址的重复命中行。
无论如何,我建议的复合索引也会加速您的 COUNT 查询。
关于PHP、MySQL : Is it possible to cache a subquery?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26486326/