php中strtotime函数性能分析


Posted in PHP onNovember 20, 2016

最近在做一个游戏数据统计后台,最基础的功能是通过分析注册登录日志来展示用户数据。在公司内部测试,用户量很少,所以就没有发现什么性能问题。但是这两天一起放到真实的测试环境,用户量噌噌地就涌进来了,从下午开始,在线人数的统计开始卡,几秒钟才返回数据;注册人数的查询速度还行。到了晚上,在线人数的统计基本上就加载超时打不开了。虽然不知他们游戏端那边什么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 相关文章推荐
用php来检测proxy
Oct 09 PHP
php foreach 参数强制类型转换的问题
Dec 10 PHP
php下通过curl抓取yahoo boss 搜索结果的实现代码
Jun 10 PHP
PHP性能优化工具篇Benchmark类调试执行时间
Dec 06 PHP
二招解决php乱码问题
Mar 25 PHP
如何获知PHP程序占用多少内存(memory_get_usage)
Sep 23 PHP
PHP5常用函数列表(分享)
Jun 07 PHP
解析php中var_dump,var_export,print_r三个函数的区别
Jun 21 PHP
使用Discuz关键词服务器实现PHP中文分词
Mar 11 PHP
php中cookie的使用方法
Mar 29 PHP
php 判断网页是否是utf8编码的方法
Jun 06 PHP
laravel Task Scheduling(任务调度)在windows下的使用详解
Oct 22 PHP
php的socket编程详解
Nov 20 #PHP
PHP内置加密函数详解
Nov 20 #PHP
php PDO异常处理详解
Nov 20 #PHP
php.ini中date.timezone设置详解
Nov 20 #PHP
centos 7.2下搭建LNMP环境教程
Nov 20 #PHP
浅析php中array_map和array_walk的使用对比
Nov 20 #PHP
php解决DOM乱码的方法示例代码
Nov 20 #PHP
You might like
PHP正则表达式之捕获组与非捕获组
2015/11/06 PHP
深入浅析PHP无限极分类的案例教程
2016/05/09 PHP
Laravel重写用户登录简单示例
2016/10/08 PHP
PHP实现的AES双向加密解密功能示例【128位】
2018/09/03 PHP
laravel 实现设置时区的简单方法
2019/10/10 PHP
PHP图像处理 imagestring添加图片水印与文字水印操作示例
2020/02/06 PHP
关于可运行代码无法正常执行的使用说明
2010/05/13 Javascript
JavaScript中的排序算法代码
2011/02/22 Javascript
jQuery获取样式中的背景颜色属性值/颜色值
2012/12/17 Javascript
让你的博客飘雪花超出屏幕依然看得见
2013/01/04 Javascript
jquery ajax对特殊字符进行转义防止js注入使用示例
2013/11/21 Javascript
ExtJS4利根据登录后不同的角色分配不同的树形菜单
2014/05/02 Javascript
Javascript 完美运动框架(逐行分析代码,让你轻松了运动的原理)
2015/01/23 Javascript
jQuery点击改变class并toggle及toggleClass()方法定义用法
2015/12/11 Javascript
详解jquery事件delegate()的使用方法
2016/01/25 Javascript
jQuery实现图片加载完成后改变图片大小的方法
2016/03/29 Javascript
基于JavaScript代码实现自动生成表格
2016/06/15 Javascript
select隐藏选中值对应的id,显示其它id的简单实现方法
2016/08/25 Javascript
JS图片放大效果简单实现代码
2016/09/08 Javascript
AngularJS动态绑定HTML的方法分析
2016/11/07 Javascript
浅谈VUE中演示v-for为什么要加key
2020/01/16 Javascript
vue-cli 3如何使用vue-bootstrap-datetimepicker日期插件
2021/02/20 Vue.js
[02:59]2014DOTA2西雅图国际邀请赛 圆满落幕中国夺冠
2014/07/23 DOTA
Python中无限元素列表的实现方法
2014/08/18 Python
详解JavaScript编程中的window与window.screen对象
2015/10/26 Python
Python随机读取文件实现实例
2017/05/25 Python
python实现mask矩阵示例(根据列表所给元素)
2020/07/30 Python
GEOX鞋美国官方网站:意大利会呼吸的鞋
2017/07/12 全球购物
Holiday Inn中国官网:IHG旗下假日酒店预订
2018/04/08 全球购物
大专生工程监理求职信
2013/10/04 职场文书
物流司机岗位职责
2013/12/28 职场文书
学习新党章思想汇报
2014/01/09 职场文书
长江七号观后感
2015/06/11 职场文书
2015年学校教科室工作总结
2015/07/20 职场文书
《自然之道》读后感3篇
2019/12/17 职场文书
在HTML5 localStorage中存储对象的示例代码
2021/04/21 Javascript