duanjuhuo8772 2014-10-21 12:07
浏览 36
已采纳

PHP,MySQL:是否可以缓存子查询?

I am working on a page-hit counter. The owner of a page will place on the page a little counter image with a link to my script in a web server; when somebody opens the page in their browser, my script will get invoked and generate an image of the hit number to be sent back to the browser.

From $_SERVER['HTTP_REFERER'] I get the page URL in order to identify the page ID: $page_id, and from $_SERVER['REMOTE_ADDR'] — viewer's host's IP: $ip, since I count only unique IPs. These data are collected in table Hits(page_id, ip).

In order to count the previous hits, I count the number of stored IPs for the given page:

$res1 = mysqli_query($DB, "SELECT ip FROM Hits WHERE page_id='$page_id'");
$number_of_hits = mysqli_num_rows($res1);

Now I need to test whether the newly arrived IP is not listed among the old ones, otherwise I would discard it and wouldn't increment the counter. I can either run a loop through the rows already found by the query, or issue another query:

$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;

But the second query is essentially redundant and as resource-consuming, as the first one; it would be much more efficient just to search through the small result obtained in the first query, than through the whole table in the second one.

I wish I could store the first query in a virtual table in the memory named, say, IPs_for_given_page (maybe somehow referred in $res1), and reduce the second query to

$res2 = mysqli_query($DB, "SELECT ip FROM IPs_for_given_page WHERE ip='$ip'");
$number_of_new_hit_occasions = mysqli_num_rows($res2);

Is it possible in any way?

  • 写回答

1条回答 默认 最新

  • doutang1873 2014-10-21 12:42
    关注

    There's no way to cache results as you mention. But there is a more efficient way to do what you're trying to do.

    To count rows, use this kind of query and retrieve the one-row result set. This is much faster than counting rows in a resultset.

    SELECT COUNT(*) FROM Hits WHERE page_id=<<whatever>>
    

    You can automate the deduplication of ip numbers by doing two things:

    First, create a compound unique index on (page_id,ip).

    Second, use this SQL statement to insert the hit row.

    INSERT IGNORE INTO Hits (page_id, ip) VALUES (<<whatever>>, <<whatever>>) 
    

    The unique index combined with the IGNORE clause together prevent MySQL from accepting duplicate hit rows for the same ip address.

    For what it's worth, the compound index I've suggested will also accelerate your COUNT query.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?