php中strtotime函数性能分析

作者:hebedich 时间:2023-11-22 13:21:05 

最近在做一个游戏数据统计后台,最基础的功能是通过分析注册登录日志来展示用户数据。在公司内部测试,用户量很少,所以就没有发现什么性能问题。但是这两天一起放到真实的测试环境,用户量噌噌地就涌进来了,从下午开始,在线人数的统计开始卡,几秒钟才返回数据;注册人数的查询速度还行。到了晚上,在线人数的统计基本上就加载超时打不开了。虽然不知他们游戏端那边什么BUG,玩家那边登录经常出问题,导致在线人数和注册人数并不是很多。但是就这一点数据量我这边查询的速度也不行,这就很尴尬了。

现在他们那边在查游戏的BUG,我这边也在看统计后台的代码到底性能出在哪里。首先说明一下,我统计用的数据是从库,他们游戏用的是主库,再说我这边管理员人数就几个,不可能会影响到游戏服的性能问题。

今天项目组长把数据库都导过来到公司内的服务器。我拷了一份到本机,看看统计平台的性能问题出在哪里。然后却发现,居然连注册统计都非常卡,服务器上是两秒左右返回,本机要二十几秒,还经常超时(PHP的默认配置是30秒超时);在线统计的就不用说了肯定打不开。看了一下数据库,当天的注册记录也就 3500 条左右(有假数据),每五分钟统计一次,一天就是统计 288 次。当然这里肯定不是循环查询数据库288次,那样会被骂死的吧。

统计时间段内的注册数,逻辑也非常简单,就是每个时间段遍历一次数据,比较时间大小,符合就+1。但是为什么这么简单的逻辑,也就一百万次循环,怎么会跑出了足足半分钟的时间那么久呢?

关键问题就出在于 时间比较这里了,我们都知道,时间戳是比较时间大小的一个比较科学的方法,而数据库里记录的时间一般都是以 YYYY-mm-dd HH:ii:ss 的形式,PHP里有strtotime的函数转换成时间戳。然而在288个for * 3500个foreach 的加持之后,这里的执行时间长达半分钟。


$nowDayDT = strtotime( date('Y-m-d') );
$__startT = microtime(TRUE);
for($i=0; $i<$allTime; $i += $gapTime){
 $count = 0;
 //用于数据比较的
 $startDT = $nowDayDT+$i;
 $endDT = $nowDayDT+$i+$gapTime;
 //用于显示的
 $xAxis1 = date('H:i', $nowDayDT+$i);
 $xAxis2 = date('H:i', $nowDayDT+$i+$gapTime);

 foreach($rawData as $line){
   $time = strtotime($line['log_dt']);
   if( $startDT<=$time && $time<$endDT ){
     $count ++;
   }
 }
 $resArr[] = [
   'date'=>$xAxis1.'~'.$xAxis2,
   'number'=>$count
 ];
}
echo microtime(TRUE)-$__startT;

那这样的话,基本上是没办法再用这个strtotime的函数的了,那还有什么办法比较时间大小呢?答案很简单粗暴,PHP里面可以直接比较两个日期时间字符串!所以改过后的代码如下。然后现在的运行时间大概是 0.3秒


$__startT = microtime(TRUE);
for($i=0; $i<$allTime; $i += $gapTime){
 $count = 0;
 //用于数据比较的
 $startDT = date('Y-m-d H:i:s', $nowDayDT+$i);
 $endDT = date('Y-m-d H:i:s', $nowDayDT+$i+$gapTime);
 //用于显示的
 $xAxis1 = date('H:i', $nowDayDT+$i);
 $xAxis2 = date('H:i', $nowDayDT+$i+$gapTime);

 foreach($rawData as $line){
   $time = $line['log_dt'];
   if( $startDT<=$time && $time<$endDT ){
     $count ++;
   }
 }
 $resArr[] = [
   'date'=>$xAxis1.'~'.$xAxis2,
   'number'=>$count
 ];
}
echo microtime(TRUE)-$__startT;

遍历再优化

大家可能发现一个问题,for 里面嵌套一个 foreach,这性能有点担忧,其中里面的 foreach 有必要完全遍历吗?其实是不必的。只要查SQL数据的时候,按时间排序排出来。优化后的时间比较算法如下:


for{ ...
foreach($rawData as $line){
 $time = $line['log_dt'];//strtotime($line['log_dt']);
 //优化算法计算
 if($time<$startDT) continue;  //小于开始时间则跳过
 if($time>=$endDT) break;    //大于结束时间则结束
 $count ++;            //否则为符合条件
 //原始的算法
//  if( $startDT<=$time && $time<$endDT ){
//    $count ++;
//  }
}
...}

这里巧用了 continue 和 break 关键字,用于跳过一次循环和结束整个循环。这次的话,一天中刚开始的时间统计中,后面很大一部分数据的都可以直接跳过。最后总遍历时间缩短为约0.12秒 。

总结,在大型的数据处理中,应该尽量避免在遍历中进行数据的转换,避免用一些原理复杂的函数。如strtotime

标签:php,strtotime函数
0
投稿

猜你喜欢

  • QQ在线客服网页代码大全

    2008-01-17 18:28:00
  • 解决 IE6 内存泄露的另类方法

    2008-07-06 23:05:00
  • python moviepy 的用法入门篇

    2022-09-03 11:41:16
  • Pycharm添加虚拟解释器报错问题解决方案

    2022-05-28 04:07:53
  • 对python读写文件去重、RE、set的使用详解

    2022-09-25 04:33:48
  • Python:二维列表下标互换方式(矩阵转置)

    2022-07-09 13:29:58
  • 基于Python实现简易学生信息管理系统

    2021-04-07 23:19:49
  • JavaScript 实现 Konami Code

    2009-05-26 12:44:00
  • 详解vue3中组件的非兼容变更

    2024-04-28 09:23:04
  • Git配置.gitignore文件忽略被指定的文件上传

    2022-09-23 03:00:08
  • Python3如何使用多线程升程序运行速度

    2023-02-06 05:11:42
  • 使用pandas读取文件的实现

    2022-10-20 14:00:42
  • 微信公众平台开发教程⑤ 微信扫码支付模式介绍

    2023-11-14 10:40:10
  • Python基于DFA算法实现内容敏感词过滤

    2023-07-25 20:14:11
  • Websocket通信协议在数字孪生中的应用

    2024-04-30 08:55:46
  • SQL Server 2008主要功能在兼容性上的问题

    2009-03-25 16:43:00
  • Linux操作系统中如何安装MySQL数据库

    2007-10-26 15:58:00
  • nodejs开发——express路由与中间件

    2024-05-11 10:18:04
  • 区别div和span、relative和absolute、display和visibility

    2009-12-13 12:18:00
  • ORACLE中的的HINT详解

    2024-01-26 23:29:53
  • asp之家 网络编程 m.aspxhome.com