【发布时间】:2016-07-08 00:10:44
【问题描述】:
我有一个大型 mysql 数据库(几条 100000 条记录)。我使用 PDO 来访问它。我需要以大约 100 条记录为单位获取数据。 PDO::fetchall 导致记录过多,耗尽 PC 内存。 PDO::fetch 只给我一条记录。
有没有办法请求下 n 条(比如 100 条)记录?
谢谢
【问题讨论】:
-
在查询本身中使用
LIMIT子句。
我有一个大型 mysql 数据库(几条 100000 条记录)。我使用 PDO 来访问它。我需要以大约 100 条记录为单位获取数据。 PDO::fetchall 导致记录过多,耗尽 PC 内存。 PDO::fetch 只给我一条记录。
有没有办法请求下 n 条(比如 100 条)记录?
谢谢
【问题讨论】:
LIMIT 子句。
PDO::fetch 只给我一条记录。
您可以随时调用 another 来获取另一条记录。以此类推,直到获取所有记录,就像每个示例中所示:
while ($row = $stmt->fetch() {
print $row[0];
}
请注意,您也可以将PDO::MYSQL_ATTR_USE_BUFFERED_QUERY 设置为 false 以减少内存消耗
【讨论】:
MySQL 客户端-服务器协议将允许从单个响应数据包中的语句的结果集中获取一定数量 (>1) 的行(如果数据符合 224-1字节限制)。 COM_STMT_FETCH command 的字段 num rows 在 OP 的情况下可以设置为 100。
但是mysqlnd的实现目前sets this field explicitly and exclusivly to 1.
所以,是的,目前你唯一的选择似乎是一个无缓冲的查询,并且需要一个一个地获取记录的(小)网络开销,例如
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly', array(
PDO::ATTR_EMULATE_PREPARES=>false,
PDO::MYSQL_ATTR_DIRECT_QUERY=>false,
PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION
));
setup($pdo);
// use an unbuffered query
// so the complete result set isn't transfered into the php instance's memory
// before ->execute() returns
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$stmt = $pdo->prepare('SELECT id FROM soFoo WHERE id>?');
$stmt->execute( array(5) );
$rowsPerChunk = 10;
do {
// not saying that you have to use LimitIterator, it's just one example of how you can process the chunks
// and a demonstration that PDOStatement implements Traversable
// all in all the example doesn't do very useful things ;-)
$lit = new LimitIterator(new IteratorIterator($stmt), 0, $rowsPerChunk);
doSomething($lit);
}
while( $lit->getPosition()===$rowsPerChunk);
function doSomething(Iterator $it) {
foreach($it as $row) {
printf('%2d ', $row['id']); // yeah, yeah, not that useful....
}
echo "\r\n-------\r\n";
}
function setup($pdo) {
$pdo->exec('
CREATE TEMPORARY TABLE soFoo (
id int auto_increment,
primary key(id)
)
');
$stmt = $pdo->prepare('INSERT INTO soFoo VALUES ()');
for($i=0; $i<44; $i++) {
$stmt->execute();
}
}
【讨论】: