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

PHP/MYSQL:迭代数据库中的每条记录,php,mysql,loops,Php,Mysql,Loops,我对整个php/mysql都是新手。我有一周的服务器日志(大约300000条),我需要做一些分析。我计划将它们全部读入mysql数据库,然后用php进行分析 我不确定的是如何遍历它们。使用java读取文件,我将执行以下操作: Scanner s = new Scanner(myfile); while(s.hasNext()){ String line = s.nextLine(); ~~ Do something with this record. } 如何使用php遍历m

我对整个php/mysql都是新手。我有一周的服务器日志(大约300000条),我需要做一些分析。我计划将它们全部读入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
    }
$query=“从mytable中选择*”;
$result=mysql\u query($query);
$rows=mysql\u num\u rows($result);
对于($j=0;$j<$rows;++$j){
$curIndex=mysql_result($result,$j,“index”);
$curURL=mysql_result($result,$j,“某物”);
~~用这张唱片做点什么
}
因此,我在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;
}
while($startIndex<$numberOfRows){
$query=“从mytable ORDERBY mytable.index中选择*限制$startIndex,$endIndex”;
$result=mysql\u query($query);
$rows=mysql\u num\u rows($result);
对于($j=0;$j<$rows;++$j){
$curIndex=mysql_result($result,$j,“index”);
$curURL=mysql_result($result,$j,“某物”);
~~用这张唱片做点什么
}
$startIndex=$endIndex+1;
$endIndex=$endIndes+10;
}
参见此处:



根据需要对结果行执行的操作,可以使用不同的循环样式,无论是“”、“”还是“”。大多数情况下,一个简单的“while”迭代会非常好,而且非常有效。

使用
mysql\u fetch.*

$result = mysql_query(...);
while($row = mysql_fetch_assoc($result)) {
 $curIndex = $row['index'];
}
我认为这是以“流”的方式检索结果,而不是一次将它们全部加载到内存中。我不确定mysql\u result的确切功能


旁注:由于您还是新手,我建议您立即养成良好的习惯,立即跳过
mysql\ucode>函数,选择或至少选择。

您不想做
SELECT*FROM MYTABLE
如果您的表很大,那么整个内容都将存储在内存中。内存开销和数据库调用之间的权衡是批处理请求。您可以获取表中行的最小id和最大id:

SELECT MIN(ID) FROM MYTABLE;
SELECT MAX(ID) FROM MYTABLE;
现在从minId循环到maxId,每次递增10000。在伪代码中:

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;
}
for(int i=minId;i=x,ID
在理想情况下,PHP将生成聚合查询,将它们发送到MySQL,并且只得到少量行作为返回。例如,如果您正在计算两个日期之间每个严重性的日志项目数:

SELECT COUNT(*), severity 
FROM logs
WHERE date < ? AND date > ?
GROUP BY severity
选择计数(*),严重性
从日志
日期在哪里?日期>?
按严重程度分组

在PHP端做这项工作是非常不寻常的。如果您发现SQL查询的需求太复杂,无法处理(鉴于您可以控制数据库结构,这给您带来了很大的自由),更好的选择是使用Map-Reduce数据库引擎,如CouchDB。

我坚信使用Doctrine进行批处理或使用MySQL(PDO或mysqli)进行任何形式的迭代只是一种幻觉

@dimitri-k提供了一个很好的解释,特别是关于工作单元的解释。问题在于未命中引导:“$query->iterate()”,它实际上不会在数据源上进行迭代。它只不过是一个\Traversable wrapper环绕已完全获取的数据源

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

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原则或DQL或纯SQL来流式处理繁重的表。但是您觉得合适:

为什么使用PDO或mysqli更好?这是一个标准还是一场霍利战争?一般来说,要查找的术语是对象关系映射(ORM)。有不同的标准,但我不认为这是圣战。很自然,一边是OO,另一边是关系形式主义,需要一些映射。而且不用手工操作总是一件好事。@Frank:PDO和mysqli恐怕都与ORM无关,它们只为数据库连接提供一个OO接口,数据仍然像往常一样是关系型的。这就是我在第三个示例中使用
LIMIT
所做的,除了我的解决方案允许按ID以外的其他内容对结果进行排序。我的版本更有效,因为您只提取x和y之间的行。使用LIMIT可以提取所有内容,然后获取起始ID和结束ID指定的任何行(这里的startIndex和endIndex ID不是表的主ID,而是前面查询生成的结果的行号)好的,我同意。这只是一个MYSQL优化。这不会占用大量内存吗?这是否有一些底层方法来获取所需的内容?任何过滤器都应该应用于底层SQL,SQL语句应该只生成所需的记录,然后PHP将遍历这些记录,以达到您的目的。如果您有一个大型数据集,请考虑使用单独的“页面”:内存,事实上,您需要使用返回的所有记录(如果不需要,则调整SQL),这些都是内置的PHP函数,因此很可能是最好的方法OK,因此执行我在第三个示例中所做的操作是不必要的,而且已经在幕后完成了?很酷。看起来mysql\u查询返回了一个资源。“资源是一个特殊变量,
namespace Doctrine\DBAL\Driver\Mysqli\MysqliStatement

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

    return new \ArrayIterator($data);
}