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网站安装程序制作的原理、步骤、注意事项和示例代码
Aug 01 PHP
比较简单实用的PHP无限分类源码分享(思路不错)
Oct 13 PHP
php中将汉字转换成拼音的函数代码
Sep 08 PHP
PHP URL参数获取方式的四种例子
Feb 28 PHP
php 购物车完整实现代码
Jun 05 PHP
php内嵌函数用法实例
Mar 20 PHP
今天你说520了吗?不仅有php表白书还有java表白神器
May 20 PHP
php封装的数据库函数与用法示例【参考thinkPHP】
Nov 08 PHP
php base64 编码与解码实例代码
Mar 21 PHP
作为PHP程序员你要知道的另外一种日志
Jul 30 PHP
php使用mysqli和pdo扩展,测试对比连接mysql数据库的效率完整示例
May 09 PHP
PHP使用PDO实现mysql防注入功能详解
Dec 20 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
ThinkPHP模板中数组循环实例
2014/10/30 PHP
php 多继承的几种常见实现方法示例
2019/11/18 PHP
php 使用 __call实现重载功能示例
2019/11/18 PHP
正则表达式判断是否存在中文和全角字符和判断包含中文字符串长度
2008/09/27 Javascript
jQuery Ajax 全解析
2009/02/08 Javascript
JS target与currentTarget区别说明
2011/08/28 Javascript
Jquery上传插件 uploadify v3.1使用说明
2012/06/18 Javascript
jquery实现不同大小浏览器使用不同的css样式表的方法
2014/04/02 Javascript
jQuery中get和post方法传值测试及注意事项
2014/08/08 Javascript
JS验证IP,子网掩码,网关和MAC的方法
2015/07/02 Javascript
JS实现的多张图片轮流播放幻灯片效果
2016/07/22 Javascript
Angularjs实现mvvm式的选项卡示例代码
2016/09/08 Javascript
详解webpack进阶之loader篇
2017/08/23 Javascript
详解react-native-fs插件的使用以及遇到的坑
2017/09/12 Javascript
Node.js引入UIBootstrap的方法示例
2018/05/11 Javascript
vue2过滤器模糊查询方法
2018/09/16 Javascript
解决Vue中引入swiper,在数据渲染的时候,发生不滑动的问题
2018/09/27 Javascript
微信小程序实现评论功能
2018/11/28 Javascript
详解webpack4.x之搭建前端开发环境
2019/03/28 Javascript
跟混乱的页面弹窗说再见
2019/04/11 Javascript
vue 获取及修改store.js里的公共变量实例
2019/11/06 Javascript
JavaScript原型继承和原型链原理详解
2020/02/04 Javascript
electron踩坑之dialog中的callback解决
2020/10/06 Javascript
element-plus一个vue3.xUI框架(element-ui的3.x 版初体验)
2020/12/02 Vue.js
[55:25]VGJ.T vs Optic Supermajor小组赛D组 BO3 第三场 6.3
2018/06/04 DOTA
python3.4下django集成使用xadmin后台的方法
2017/08/15 Python
分析Python读取文件时的路径问题
2018/02/11 Python
分布式全文检索引擎ElasticSearch原理及使用实例
2020/11/14 Python
纯css3实现宠物小鸡实例代码
2018/10/08 HTML / CSS
仓库门卫岗位职责
2013/12/22 职场文书
毕业生个人投资创业计划书
2014/01/04 职场文书
法学专业求职信
2014/07/15 职场文书
资源环境与城乡规划管理专业自荐书
2014/09/26 职场文书
商场圣诞节活动总结
2015/05/06 职场文书
学生犯错保证书
2015/05/09 职场文书
土木工程毕业答辩开场白
2015/05/29 职场文书