PHP / MYSQL:迭代数据库中的每条记录

时间:2010-11-11 14:16:12

标签: php mysql loops

我是整个php / mysql的新手。我有一周的服务器日志(大约300,000项),我需要做一些分析。我打算将它们全部读入mysql数据库,然后用php分析它们。

我不确定的是如何迭代它们。使用java读取文件我会做这样的事情:

Scanner s = new Scanner(myfile);
while(s.hasNext()){
    String line = s.nextLine();
    ~~ Do something with this record. 
}

如何使用php迭代mysql数据库中的所有记录?我认为像这样的东西需要愚蠢的记忆。

    $query = "SELECT * FROM mytable";
    $result = mysql_query($query);
    $rows = mysql_num_rows($result);
    for($j = 0; $j < $rows; ++$j){
            $curIndex   = mysql_result($result,$j,"index");
            $curURL     = mysql_result($result,$j,"something");
            ~~ Do something with this record
    }

所以我在select语句中添加了一个限制,我重复一遍,直到所有记录都循环完毕。有更标准的方法吗?有没有内置的可以做到这一点?

while($startIndex < $numberOfRows){

    $query = "SELECT * FROM mytable ORDERBY mytable.index LIMIT $startIndex,$endIndex";
    $result = mysql_query($query);
    $rows = mysql_num_rows($result);
    for($j = 0; $j < $rows; ++$j){
            $curIndex   = mysql_result($result,$j,"index");
            $curURL     = mysql_result($result,$j,"something");
            ~~ Do something with this record
    }
    $startIndex = $endIndex + 1;
    $endIndex = $endIndes + 10;
}

5 个答案:

答案 0 :(得分:5)

如果你的桌子很大,你不想做SELECT * FROM MYTABLE,你将会把整件事放在记忆中。内存开销和数据库调用之间的权衡将是批处理请求。您可以在表格中获取行的最小和最大ID:

SELECT MIN(ID) FROM MYTABLE;
SELECT MAX(ID) FROM MYTABLE;

现在从minId循环到maxId,每次增加10,000。在伪代码中:

for (int i = minId; i < maxId; i = i + 10000) {
   int x = i;
   int y = i + 10000;
   SELECT * FROM MYTABLE WHERE ID >= x AND ID < y;
}

答案 1 :(得分:4)

见这里:

http://www.tizag.com/mysqlTutorial/

http://www.tizag.com/mysqlTutorial/mysqlfetcharray.php

<?php
// Make a MySQL Connection
$query = "SELECT * FROM example"; 

$result = mysql_query($query) or die(mysql_error());


while($row = mysql_fetch_array($result)){
    echo $row['name']. " - ". $row['age'];
    echo "<br />";
}
?>

根据您对结果行的需要,您可以使用不同的循环样式,无论是“while”,“for each”还是“for x to x”。大多数情况下,简单的“while”迭代将很棒,并且效率很高。

答案 2 :(得分:2)

使用mysql_fetch_*

$result = mysql_query(...);
while($row = mysql_fetch_assoc($result)) {
 $curIndex = $row['index'];
}

我认为以“流式”方式检索结果,而不是一次性将它们全部加载到内存中。我不确定mysql_result到底是做什么的。

附注:既然你还是新人,我建议立即养成良好的习惯并立即跳过mysql_函数并转到PDO或至少mysqli

答案 3 :(得分:0)

在理想的世界中,PHP会生成聚合查询,将它们发送到MySQL,并且只返回少量行。例如,如果您计算两个日期之间每个严重性的日志项数:

SELECT COUNT(*), severity 
FROM logs
WHERE date < ? AND date > ?
GROUP BY severity

在PHP方面做的工作很不寻常。如果你发现你需要处理太复杂的SQL查询来处理(考虑到你可以控制你的数据库结构,让你有很大的自由),一个更好的选择就是转移到Map-Reduce数据库引擎就像CouchDB。

答案 4 :(得分:0)

我坚信使用Doctrine进行批处理或使用MySQL(PDO或mysqli)进行任何迭代都只是一种错觉。

@ dimitri-k提供了一个很好的解释,特别是关于工作单元。问题是导致错过:&#34; $ query-&gt; iterate()&#34;它并没有真正迭代数据源。已经完全获取数据源的只是一个\ Traversable wrapper

一个例子表明即使从图片中完全删除Doctrine抽象层,我们仍会遇到内存问题

echo 'Starting with memory usage: ' . memory_get_usage(true) / 1024 / 1024 . " MB \n";

$pdo  = new \PDO("mysql:dbname=DBNAME;host=HOST", "USER", "PW");
$stmt = $pdo->prepare('SELECT * FROM my_big_table LIMIT 100000');
$stmt->execute();

while ($rawCampaign = $stmt->fetch()) {
    // echo $rawCampaign['id'] . "\n";
}

echo 'Ending with memory usage: ' . memory_get_usage(true) / 1024 / 1024 . " MB \n";

<强>输出:

Starting with memory usage: 6 MB 
Ending with memory usage: 109.46875 MB

这里,令人失望的 getIterator()方法:

namespace Doctrine\DBAL\Driver\Mysqli\MysqliStatement

/**
 * {@inheritdoc}
 */
public function getIterator()
{
    $data = $this->fetchAll();

    return new \ArrayIterator($data);
}

您可以使用我的小库来实际使用PHP Doctrine或DQL或纯SQL来传输繁重的表。但是你找到了合适的:https://github.com/EnchanterIO/remote-collection-stream