在PHP中循环遍历大数据数组

时间:2014-04-15 09:52:30

标签: php mysql memory memory-management

我有一个包含100,000个用户个人信息的数组(ID,姓名,电子邮件等)。我需要循环遍历数组的每一行,并根据行数据将mysql记录插入表中。我的问题是我在大约70,000行后耗尽内存。

我的代码:

if(!empty($users)){
    $c = 0;
        foreach($users as $user){

            $message = // Some code to create custom email
            queue_mail_to_send($user->user_email, $subject, $message, $db_options, $mail_options, $mail_queue);
        }
}

背景:

我正在建立一个电子邮件系统,向我的网站用户发送一封电子邮件。上面的代码循环遍历用户数组并执行函数'queue_mail_to_send',该函数将mysql行插入到电子邮件队列表中。 (我正在使用PEAR库错开电子邮件发送)

问题:

我知道我只是在一次执行中尝试做太多而耗费内存。那么有没有人知道更好的方法而不是试图在一个大循环中执行所有东西?

由于

5 个答案:

答案 0 :(得分:3)

我认为减少脚本的有效负载会很麻烦,并且不会给您带来满意的结果。如果您有可能这样做,我建议您记录已经处理过的行,并让脚本运行下一行x行。如果您可以使用cronjob,则可以暂存邮件,并让cronjob每隔5分钟将邮件添加到队列中,直到所有用户都被处理完毕。

最简单的方法是存储某个地方,即您处理的最高用户ID。我不建议您存储用户数,因为在批次之间可以添加或删除用户,导致用户无法接收电子邮件。但是,如果您按用户ID(假设您为id使用自动递增列)进行排序,则可以确保每个用户都得到处理。

因此,您的用户查询类似于:

SELECT * FROM users WHERE user_id > [highest_processed_user_id] ORDER BY user_id LIMIT 1000

然后处理你的循环,并存储最后一个用户ID:

if(!empty($users)) {
    $last_processed_id = null;
    foreach($users as $user) {
        $message = // Message creation magic
        queue_mail_to_send( /** parameters **/ );
        $last_processed_id = $user->id;
    }

    // batch done! store processed user id
    $query = 'UPDATE mail_table SET last_processed_user_id = '. $last_processed_id; // please use parameterized statements here
    // execute the query
}

在下次执行时,再次执行,直到所有用户都收到邮件。

答案 1 :(得分:1)

我和你有完全相同的问题。无论如何,@ giorgio的答案是最好的解决方案。

但是像java或python一样,我们在php中有“收益”。 @see [here](http://php.net/manual/en/language.generators.syntax.php

这是我的示例代码,我的案例是50.000条记录。我还成功测试了370.000条记录。但这需要时间。

$items = CustomerService::findAll();
        foreach ($items AS $item)
        {
            yield (new self())->loadFromResource($item);
        }

答案 2 :(得分:0)

您可以在多个操作中拆分该操作,并及时分开。 例如,只允许您的例程每分钟处理40封电子邮件,或者使用数组的数组来创建记录的“页面”(使用sql LIMIT函数)。 当你不再需要那些信息时,将数组的数组设置为null并取消设置它。

答案 3 :(得分:-1)

我认为您可以使用MySQL IN子句,而不是为每个用户执行foreach。

像 user_ids = array(1,2,3,4); //执行WHERE user_id IN($ user_ids);

发送邮件,您可以通过在$ to中提供逗号分隔的电子邮件地址来使用PHPMailer类。

答案 4 :(得分:-1)

只使用一个查询:

INSERT INTO table_name (COL1, Col2,...) SELECT COL1, COL2 FROM other_table;