Heim >Backend-Entwicklung >PHP-Tutorial >PHP处理大量数据的问题

PHP处理大量数据的问题

WBOY
WBOYOriginal
2016-06-06 20:15:331144Durchsuche

例如从两张表中分别查出上百万条数据,现在需要把这些数据组装在一起然后在插入到另外一张表中,请问除了使用数组组装外还能怎么处理,如果使用数组的话怎么才能保证不超出内存限制。

回复内容:

例如从两张表中分别查出上百万条数据,现在需要把这些数据组装在一起然后在插入到另外一张表中,请问除了使用数组组装外还能怎么处理,如果使用数组的话怎么才能保证不超出内存限制。

mysql_query函数查询的方式是查询出全部结果后缓存到内存中,这样就会出现超内存的现象,使用另外一个函数mysql_unbuffered_query可以解决这个问题,mysql_unbuffered_query不会缓存结果集,而是查询出来数据后立马对结果集进行操作,也就是便查询边返回,这样就不会出现超出内存的现象,但是使用mysql_unbuffered_query的是时候不能使用 mysql_num_rows() 和 mysql_data_seek()。并且向 MySQL 发送一条新的 SQL 查询之前,必须提取掉所有未缓存的 SQL 查询所产生的结果行。例如:

使用缓存结果集的代码:

<code>function selecttest()
    {
        try {
            $pdo = new PDO("mysql:host=localhost;dbname=test", 'root', '123456');
//            不使用缓存结果集方式
//            $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
            $sth = $pdo->prepare('select * from test');
            $sth->execute();
            echo '最初占用内存大小:' . memory_get_usage() . "\n";
            $i = 0;
            while ($result = $sth->fetch(PDO::FETCH_ASSOC)) {
                $i += 1;
                if ($i > 10) {
                    break;
                }
                sleep(1);
                print_r($result);
                echo '占用内存大小:' . memory_get_usage() . "\n";
            }
        } catch (Exception $e) {
            echo $e->getMessage();
        }
    }</code>

执行时将会报超出内存的错误:

<code>Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 204800000 bytes) in E:\ProgramDevelopment\RuntimeEnvironment\xampp\htdocs\test\test.php on line 56

Call Stack:
    0.0005     135392   1. {main}() E:\ProgramDevelopment\RuntimeEnvironment\xampp\htdocs\test\test.php:0
    0.0005     135568   2. test->selecttest() E:\ProgramDevelopment\RuntimeEnvironment\xampp\htdocs\test\test.php:85
    0.0050     142528   3. PDOStatement->execute() E:\ProgramDevelopment\RuntimeEnvironment\xampp\htdocs\test\test.php:56</code>

将上面代码中的$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);一行的注释去掉后将不在缓存结果集,这时运行该函数的结果如下:

<code>最初占用内存大小:144808
Array
(
    [id] => 1
    [a] => v
    [b] => w
    [c] => i
)
占用内存大小:145544
Array
(
    [id] => 2
    [a] => b
    [b] => l
    [c] => q
)
占用内存大小:145544
Array
(
    [id] => 3
    [a] => m
    [b] => p
    [c] => h
)
占用内存大小:145536
Array
(
    [id] => 4
    [a] => j
    [b] => i
    [c] => b
)
占用内存大小:145536</code>

可以看到,这时返回一条数据内存占用非常的小,也就700多字节,这样就不会出现超出内存的错误了。

使用数组...一起加载进内存...呵呵呵...肯定很难受的~

解决办法就是PHP的新特性...额,其实不是很新了。

迭代生成器,(迭代)生成器也是一个函数,不同的是这个函数的返回值是依次返回,而不是只返回一个单独的值.或者,换句话说,生成器使你能更方便的实现了迭代器接口.下面通过实现一个xrange函数来简单说明:

<code class="php"><?php function xrange($start, $end, $step = 1) {
    for ($i = $start; $i <= $end; $i += $step) {
        yield $i;
    }
}
 
foreach (xrange(1, 1000000) as $num) {
    echo $num, "\n";
}</code></code>

上面这个xrange()函数提供了和PHP的内建函数range()一样的功能.但是不同的是range()函数返回的是一个包含值从1到100万0的数组(注:请查看手册). 而xrange()函数返回的是依次输出这些值的一个迭代器, 而不会真正以数组形式返回.

这种方法的优点是显而易见的.它可以让你在处理大数据集合的时候不用一次性的加载到内存中.甚至你可以处理无限大的数据流.

当然,也可以不同通过生成器来实现这个功能,而是可以通过继承Iterator接口实现.但通过使用生成器实现起来会更方便,不用再去实现iterator接口中的5个方法了.

建议参考鸟哥的一片文章: 在PHP中使用协程实现多任务调度

保证不内存溢出的方法很简单,优化算法,分批次逐步完成任务,减少每次读出数据的数量。

一点一点的写

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn