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'迭代将会很好,而且效率很高。
使用mysql_fetch_*
$result = mysql_query(...);
while($row = mysql_fetch_assoc($result)) {
$curIndex = $row['index'];
}
我想在一个“流”的方式检索结果,而不是将它们全部加载到内存中一次。我不确定mysql_result
究竟做了什么。
为什么使用PDO或mysqli更好?这是标准还是冬青战争? – sixtyfootersdude 2010-11-11 14:32:22
查找的一般术语是对象关系映射(ORM)。有不同的或多或少的标准,但我不认为这是一场神圣的战争。一方面有OO,另一方面是关系形式主义,你需要一些映射是很自然的。而不是手工做这件事总是一件好事。 – Frank 2010-11-11 14:49:27
@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;
}
这就是我在第三个例子中使用'LIMIT'所做的事情,除了我的解决方案允许结果被ID以外的东西排序。 – sixtyfootersdude 2010-11-11 14:33:26
我的版本更高效,因为您只需拉出x和y之间的行。使用LIMIT,您将取出所有内容,然后获取您的开始和结束ID指定的任何行(此处的startIndex和endIndex ID不是表的主ID,而是前面生成的结果的行号查询) – 2010-11-11 14:39:09
好吧,我买了。这只是一个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
这不会使用疯狂的内存量吗?这是否有一些基本的方法来获取需要的东西? – sixtyfootersdude 2010-11-11 14:34:57
任何过滤器都应该应用到底层的SQL,SQL语句应该只产生所需的记录,然后PHP会为您的目的迭代,如果您有大数据集,请考虑使用单独的'页面' – SW4 2010-11-11 14:46:05
Re:内存,如果你需要使用所有返回的记录(如果你没有,然后调整你的SQL),这些都是内置的PHP函数,所以可能是最好的方法 – SW4 2010-11-11 14:47:03