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 相关文章推荐
Cakephp 执行主要流程
Mar 24 PHP
PHP设计模式之命令模式的深入解析
Jun 13 PHP
php实现水仙花数的4个示例分享
Apr 08 PHP
PHP链接MySQL的常用扩展函数
Oct 23 PHP
php下pdo的mysql事务处理用法实例
Dec 27 PHP
PDO防注入原理分析以及注意事项
Feb 25 PHP
php传值赋值和传地址赋值用法实例分析
Jun 20 PHP
ThinkPHP删除栏目(实现批量删除栏目)
Jun 21 PHP
关于php unset对json_encode的影响详解
Nov 14 PHP
PHP读取目录树的实现方法分析
Mar 22 PHP
PHP工厂模式、单例模式与注册树模式实例详解
Jun 03 PHP
php给数组赋值的实例方法
Sep 26 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
基于empty函数的输出详解
2013/06/17 PHP
Codeigniter生成Excel文档的简单方法
2014/06/12 PHP
PHP+HTML+JavaScript+Css实现简单爬虫开发
2016/03/28 PHP
PHP编写简单的App接口
2016/08/28 PHP
php中的单引号、双引号和转义字符详解
2017/02/16 PHP
js实现ASP分页函数 HTML分页函数
2006/09/22 Javascript
js中的window.open返回object的错误的解决方法
2009/08/15 Javascript
基于jquery的设置页面文本框 只能输入数字的实现代码
2011/04/19 Javascript
jquery中的 $(&quot;#jb51&quot;)与document.getElementById(&quot;jb51&quot;) 的区别
2011/07/26 Javascript
JavaScript 上万关键字瞬间匹配实现代码
2013/07/07 Javascript
使用js判断当前时区TimeZone是否是夏令时
2014/02/23 Javascript
Jquery对数组的操作技巧整理
2014/03/25 Javascript
原生JS实现响应式瀑布流布局
2015/04/02 Javascript
在JS方法中返回多个值的方法汇总
2015/05/20 Javascript
JS实现淡蓝色简洁竖向Tab点击切换效果
2015/10/06 Javascript
使用bat打开多个cmd窗口执行gulp、node
2017/02/17 Javascript
详解React native全局变量的使用(跨组件的通信)
2017/09/07 Javascript
js封装成插件的步骤方法
2017/09/11 Javascript
使用html+js+css 实现页面轮播图效果(实例讲解)
2017/09/21 Javascript
浅谈Vue-cli单文件组件引入less,sass,css样式的不同方法
2018/03/13 Javascript
vue2.0中set添加属性后视图不能更新的解决办法
2019/02/22 Javascript
微信小程序webview组件交互,内联h5页面并网页实现微信支付实现解析
2019/08/16 Javascript
详解Python中内置的NotImplemented类型的用法
2015/03/31 Python
python中requests模块的使用方法
2015/04/08 Python
Python实现短网址ShortUrl的Hash运算实例讲解
2015/08/10 Python
浅谈Python批处理文件夹中的txt文件
2019/03/11 Python
Python 中的参数传递、返回值、浅拷贝、深拷贝
2019/06/25 Python
python修改字典键(key)的方法
2019/08/05 Python
python列表推导式入门学习解析
2019/12/02 Python
基于nexus3配置Python仓库过程详解
2020/06/15 Python
遇到的Mysql的面试题
2014/06/29 面试题
兼职业务员岗位职责
2014/01/01 职场文书
小学生国旗下演讲稿
2014/04/25 职场文书
啦啦队口号大全
2014/06/16 职场文书
JMeter对MySQL数据库进行压力测试的实现步骤
2022/01/22 MySQL
python单向链表实例详解
2022/05/25 Python