当前位置: 首页 > news >正文

软件技术和计算机网络技术哪个好宁波seo网站

软件技术和计算机网络技术哪个好,宁波seo网站,php一键建站,网站建设全套教程含前端和后端在编写定时任务脚本的时候,经常会用到chunk和chunkById的API。 一、前言 数据库引擎为innodb。 表结构简述,只列出了本文用到的字段。 字段类型注释idint(11)IDtypeint(11)类型mark_timeint(10)标注时间(时间戳) 索引&#x…

在编写定时任务脚本的时候,经常会用到chunk和chunkById的API。

一、前言

数据库引擎为innodb。

表结构简述,只列出了本文用到的字段。

字段类型注释
idint(11)ID
typeint(11)类型
mark_timeint(10)标注时间(时间戳)

索引,也只列出需要的部分。

索引名字段
PRIMARYid
idx_sid_blogdel_marktimetype blog_del mark_time
Idx_marktimemark_time

二、需求

每天凌晨一点取出昨天标注type为99的所有数据,进行逻辑判断,然后进行其他操作。本文的重点只在于取数据的阶段。

数据按月分表,每个月表中的数据为1000w上下。

三、chunk处理数据

代码如下:

$this->dao->where('type', 99)->whereBetween('mark_time', [$date, $date+86399])->select(array('mark_time', 'id'))->chunk(1000, function ($rows){// 业务处理
});

从一个月中的数据,筛选出type为99,并且标注时间在某天的00:00:00-23:59:59的数据。可以使用到mark_time和type的索引。

type为99,一天的数据大概在15-25w上下的样子。使用->get()->toArray()内存会直接炸掉。所以使用chunk方法,每次取出1000条数据。

使用chucnk,不会出现内存不够的情况。但是性能较差。粗略估计,从一月数据中取出最后一天的数据,跑完20w数据大概需要一两分钟。

查看源码,底层的chunk方法,是为sql语句添加了限制和偏移量。

select * from users asc limit 500 offset 500;

在数据较多的时候,越往后的话效率会越慢,因为Mysql的limit方法底层是这样的。

limit 10000,10

是扫描满足条件的10010行,然后扔掉前面的10000行,返回最后最后20行。在数据较多的时候,性能会非常差。

查了下API,对于这种情况Laraverl提供了另一个API chunkById。

四、chunkById 原理

使用limit和偏移量在处理大量的数据会有性能的明显下降。于是chunkById使用了id进行分页处理。很好理解,代码如下:

select * from users where id > :last_id order by id asc limit 500;

API会自动保存最后一个ID,然后通过id > :last_id 再加上limit就可以通过主键索引进行分页。只取出来需要的行数。性能会有明显的提升。

五、chunkById的坑

API显示chunk和chunkById的用法完全相同。于是把脚本的代码换成了chunkById。

$this->dao->where('type', 99)->whereBetween('mark_time', [$date, $date+86399])->select(array('mark_time', 'id'))->chunkById(1000, function ($rows){// 业务处理
});

在执行脚本的时候,1月2号和1月1号的数据没有任何问题。执行速度快了很多。但是在执行12月31号的数据的时候,发现脚本一直执行不完。

在定位后发现是脚本没有进入业务处理的部分,也就是sql一直没有执行完。当时很疑惑,因为刚才执行的没问题,为什么执行12月31号的就出问题了呢。

于是查看sql服务器中的执行情况。

show full processlist;

发现了问题。上节说了chunkById的底层是通过id进行order by,然后limie取出一部分一部分的数据,也就是我们预想的sql是这样的。

select * from tabel where type = 99 and mark_time between :begin_date and :end_date limit 500;

explain出来的情况如下:

在这里插入图片描述

实际上的sql是这样的:

select * from tabel where type = 99 and mark_time between :begin_date and :end_date order by id limit 500;

实际explain出来的情况是这样的:

在这里插入图片描述

chunkById会自动添加order by id。innodb一定会使用主键索引。那么就不会再使用mark_time的索引了。导致sql执行效率及其缓慢。

六、解决方法

再次查看chunkById的源码。

/*** Chunk the results of a query by comparing IDs.** @param  int  $count* @param  callable  $callback* @param  string|null  $column* @param  string|null  $alias* @return bool*/
public function chunkById($count, callable $callback, $column = null, $alias = null)
{$column = $column ?? $this->defaultKeyName();$alias = $alias ?? $column;$lastId = null;do {$clone = clone $this;// We'll execute the query for the given page and get the results. If there are// no results we can just break and return from here. When there are results// we will call the callback with the current chunk of these results here.$results = $clone->forPageAfterId($count, $lastId, $column)->get();$countResults = $results->count();if ($countResults == 0) {break;}// On each chunk result set, we will pass them to the callback and then let the// developer take care of everything within the callback, which allows us to// keep the memory low for spinning through large result sets for working.if ($callback($results) === false) {return false;}$lastId = $results->last()->{$alias};unset($results);} while ($countResults == $count);return true;
}

能看到这个方法有四个参数count,callback,column,alias。
默认的column为null,第一行会进行默认赋值。

/*** Get the default key name of the table.** @return string*/
protected function defaultKeyName()
{return 'id';
}

能看到默认的column为id。
进入forPageAfterId方法。

/*** Constrain the query to the next "page" of results after a given ID.** @param  int  $perPage* @param  int|null  $lastId* @param  string  $column* @return \Illuminate\Database\Query\Builder|static*/
public function forPageAfterId($perPage = 15, $lastId = 0, $column = 'id')
{$this->orders = $this->removeExistingOrdersFor($column);if (! is_null($lastId)) {$this->where($column, '>', $lastId);}return $this->orderBy($column, 'asc')->limit($perPage);
}

能看到如果lastId不为0则自动添加where语句,还会自动添加order by column。

看到这里就明白了。上文的chunkById没有添加column参数,所以底层自动添加了order by id。走了主键索引,没有使用上mark_time的索引。导致查询效率非常低。

chunkById的源码显示了我们可以传递一个column字段来让底层使用这个字段来order by。

代码修改如下:

$this->dao->where('type', 99)->whereBetween('mark_time', [$date, $date+86399])->select(array('mark_time', 'id'))->chunkById(1000, function ($rows){// 业务处理
}, 'mark_time');

这样最后执行的sql如下:

select * from tabel where type = 99 and mark_time between :begin_date and :end_date order by mark_time limit 500;

再次执行脚本,大概执行一次也就十秒作用了,性能提升显著。

七、总结

使用 chunkById 或者 chunk 方法的时候不要添加自定义的排序,chunk和chunkById的区别就是chunk是单纯的通过偏移量来获取数据,chunkById进行了优化,不使用偏移量,使用id过滤,性能提升巨大。在数据量大的时候,性能可以差到几十倍的样子。

而且使用chunk在更新的时候,也会遇到数据会被跳过的问题。详见解决Laravel中chunk方法分块处理数据的坑

同时chunkById在你没有传递column参数时,会默认添加order by id。可能会遇到索引失效的问题。解决办法就是传递column参数即可。

本人感觉chunkById不光是根据Id分块,而是可以根据某一字段进行分块,这个字段是可以指定的。叫chunkById有一些误导性,chunkByColumn可能更容易理解。

使用chunkById时不要加排序
使用chunkById比chunk更快

原文

http://www.dt0577.cn/news/17155.html

相关文章:

  • 上海专业高端网站建设服务竞价托管 微竞价
  • 怎么用源码做网站seo优化排名方法
  • 海搜网做的网站怎么办怎么注册自己的网站域名
  • 金融行业网站制作网站seo属于什么专业
  • 怎样在设计网站做图赚钱吗商品推广软文写作500字
  • 上海在线做网站营销推广活动策划方案
  • wordpress建站两秒打开关键词优化排名用哪些软件比较好
  • 策划公司组织结构图北京seo外包
  • wordpress页面如何排序学seo哪个培训好
  • 湖南衡阳市建设工程造价网站营销推广app
  • 平台是什么意思群排名优化软件官网
  • 微商手机网站制作公司深圳关键词排名推广
  • 公司网站建设内容建议百度网盘下载app
  • 合肥一浪网络科技有限公司seo优化价格
  • 理财网站建设的毕业论文活动策划公司
  • 成都网站优化哪家好今天新闻联播
  • 有哪些国外网站做的好的效果图精准营销的典型案例
  • 怎么样在网站上做跳转乔拓云网站建设
  • 唐山建设公司网站临沂seo建站
  • 做微博这样的网站吗软文广告推广
  • 专业建站公司设计百度推广app
  • 手机网站页面设计百度首页入口
  • 网站百度百科怎么做班级优化大师使用指南
  • 接做网站简介百度主页入口
  • 网站建设课程论文网上推
  • 北京中国建设银行招聘信息网站宁波网络推广软件
  • 上市公司协会网站建设汇报在线网页制作
  • 开发做网站公司文章发布在哪个平台好
  • 网站管理与维护方案网络推广公司怎么找客户
  • 没有域名能做网站吗全国推广优化网站