针对几千条以上的数组,如何循环呢?

2017-03-12 20:01:57 +08:00
 MrMike

我需要循环这个大数组(web 的方式),然后组合成一个字符串,再在循环外进行数据的插入工作。但是现在循环超过 5000 条时,页面就不动了,内存都用完了。有没有好的建议和解决方案,如何处理这种大数组的循环呢?

3831 次点击
所在节点    PHP
30 条回复
herozhang
2017-03-13 10:05:51 +08:00
@MrMike 代码里面尝试把不用的字符串变量 unset 一下?
MrMike
2017-03-13 10:19:07 +08:00
@herozhang 都是要用的字符串,没有不用的哦。我现在发现,可能是因为在循环里面有数据库的查询的问题。但是又必须要针对数据库进行比对,这个有没有好的解决方案?
Immortal
2017-03-13 10:29:43 +08:00
每次遇到这类问题我总觉得是架构上不合理..
zhs227
2017-03-13 10:32:42 +08:00
php 里有一种叫做 generator ,应该可以解决这个问题。

```
生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低。

生成器允许你在 foreach 代码块中写代码来迭代一组数据而不需要在内存中创建一个数组, 那会使你的内存达到上限,或者会占据可观的处理时间。相反,你可以写一个生成器函数,就像一个普通的自定义函数一样, 和普通函数只返回一次不同的是, 生成器可以根据需要 yield 多次,以便生成需要迭代的值。
```
MrMike
2017-03-13 10:49:38 +08:00
@Immortal 数据库结构是:
主表:product ,属性表: product_attribute(product_id 为外链),产品图片表: product_image(product_id 为外链),产品价格表: product_price(product_id 为外链),产品型号表: product_model ,型号表跟主表(product)是一对多的关系,同一个型号,可能因为型号里面的品牌不同,会有不同的产品,所以在主表 product 里面有一个 model_id 字段关联 product_model 表,主表 product 里面还有一个所有者 creator_id 字段,关联当前产品的所有者。
在循环中,需要根据传递的所有者 ID 和型号名称,去查询当前产品是否已经存在数据库中了,同一个用户只能上传一个相同型号的产品。

不知道这样的结构,有没有问题呢?谢谢哈。
mrgeneral
2017-03-13 11:03:27 +08:00
yield 是一种方法。

另外就是优化逻辑啊,你无脑一个循环查询,先从数组中把查询条件提取出来,一次性查询完,然后再用结果和原数组进行逻辑处理,最后得到的结果再插入到数据库。

两次数据库操作,几千条数组 PHP 处理其实是很快的,关于内存,只选择必要数据就好了。

如果必要数据都超过限制,就不要一次性查询完,用 yield 分批查询,也比无脑循环查询好。
AbrahamGreyson
2017-03-13 11:03:48 +08:00
@MrMike 具体代码没看,五千次循环查询,建议用队列。
notgod
2017-03-13 11:59:13 +08:00
看不下去了, 这个问题能在首页 2 天.....
这个不能算问题的少年 从头到尾都是个逻辑问题

你把详细需求列出来 一个一个解决

#1 预期 超 1W+的循环, 这个循环根本不是问题, 无论是使用 yield 还是自循环

#2. 1 数据库查询瓶颈 就是检查数据库的重复记录, 这个可以使用 Redis/Memcache 缓存
先把 mysql 的需要比较重复的字段 读出来, 需要比较的写到 KVDB 里, 后期每次检查 /更新+新增加到 KVDB
如果闲 KVDB 麻烦, 别人封装好了 www.phpfastcache.com , 可以 file 可以 sqlite

#2. 2 MYSQL 建好索引 /使用 IN 进行查询 性能开销没你想的那么大

#3 插入瓶颈
这个解决办法不是很多? 你换个逻辑 为什么一定要循环后直接写入? 而且还是单条插次
不能按 sql 的格式 写到本地文本文件?
先在#2 的步骤 使用 if 去判断是不是重复 如果不重复 生成个格式 写到本地文件里
然后 批量导入 使用 mysql 的批量导入命令
可以使用 shell_exec 调用 mysql 的 cli 运行, 也可以直接插入
本来一次插一条 这个过程都需要和 mysql 连接一次
如果你一次性插 1000 条 也是连接一次
一般 mysql 连接数设的都是 100-500
而且很多人没关闭连接的习惯.....

你的问题在于优化业务逻辑, 不是代码 不是代码 不是代码
MrMike
2017-03-13 12:19:40 +08:00
@notgod 非常感谢。项目本身就已经用了 redis 来缓存,只是 redis 和项目在同一个服务器上,因为对它不熟悉,在其他功能上, redis 经常会出错,所以一直没想把数据全部缓存到 redis 上面。我再试试。
mingyun
2017-04-22 19:55:23 +08:00
cli 执行 执行完一次 sleep 下

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/346901

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX