PHP/MYSQL:遍历数据库中的每条记录

问题描述:

我是新来的整个PHP/MySQL的东西。我有一周的服务器日志(约300,000项),我需要做一些分析。我打算将它们全部读入一个mysql数据库,然后用php进行分析。PHP/MYSQL:遍历数据库中的每条记录

我不确定的事情是如何迭代它们。使用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 
    } 

所以我增加了一个限制选择语句,我重复,直到所有记录已经循环。有没有更标准的方法来做到这一点?有没有内置的,会做到这一点?

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; 
} 

在这里看到:

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'迭代将会很好,而且效率很高。

+0

这不会使用疯狂的内存量吗?这是否有一些基本的方法来获取需要的东西? – sixtyfootersdude 2010-11-11 14:34:57

+0

任何过滤器都应该应用到底层的SQL,SQL语句应该只产生所需的记录,然后PHP会为您的目的迭代,如果您有大数据集,请考虑使用单独的'页面' – SW4 2010-11-11 14:46:05

+0

Re:内存,如果你需要使用所有返回的记录(如果你没有,然后调整你的SQL),这些都是内置的PHP函数,所以可能是最好的方法 – SW4 2010-11-11 14:47:03

使用mysql_fetch_*

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

我想在一个“流”的方式检索结果,而不是将它们全部加载到内存中一次。我不确定mysql_result究竟做了什么。

注意:由于您还是新手,我建议您立即进入良好的使用习惯,并立即跳过mysql_的功能,并去PDO或至少mysqli

+0

为什么使用PDO或mysqli更好?这是标准还是冬青战争? – sixtyfootersdude 2010-11-11 14:32:22

+0

查找的一般术语是对象关系映射(ORM)。有不同的或多或少的标准,但我不认为这是一场神圣的战争。一方面有OO,另一方面是关系形式主义,你需要一些映射是很自然的。而不是手工做这件事总是一件好事。 – Frank 2010-11-11 14:49:27

+0

@Frank:PDO和mysqli都不和ORM有任何关系,恐怕它们只是提供了一个到数据库连接的OO接口,数据仍然是一如既往的关系。 – 2010-11-11 15:54:05

如果你的表很大,你不想做一个SELECT * FROM MYTABLE,你会把所有的东西放在内存中。内存开销和数据库调用之间的折衷是批量请求。从minId

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

现在环路maxId,通过增加每说一次10000:你可以得到行的最小和最大的ID在表格中。在伪代码中:

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; 
} 
+0

这就是我在第三个例子中使用'LIMIT'所做的事情,除了我的解决方案允许结果被ID以外的东西排序。 – sixtyfootersdude 2010-11-11 14:33:26

+0

我的版本更高效,因为您只需拉出x和y之间的行。使用LIMIT,您将取出所有内容,然后获取您的开始和结束ID指定的任何行(此处的startIndex和endIndex ID不是表的主ID,而是前面生成的结果的行号查询) – 2010-11-11 14:39:09

+0

好吧,我买了。这只是一个MYSQL优化。 – sixtyfootersdude 2010-11-11 18:25:47

在理想的世界中,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包装左右已经完全提取数据源。

证明,即使从图片完全去除主义抽象层,我们仍然会碰到内存的例子发出

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