是否可以遍历查询,以便如果(例如)找到500,000行,它将返回前10,000个的结果,然后再次重新运行查询?
所以,我想要做的是运行查询并构建一个数组,如下所示:
$result = pg_query("SELECT * FROM myTable");
$i = 0;
while($row = pg_fetch_array($result) ) {
$myArray[$i]['id'] = $row['id'];
$myArray[$i]['name'] = $row['name'];
$i++;
}
但是,我知道会有几十万行,所以我想分批进行10,000次...... 1- 9,999然后10,000 - 10,999等等...原因是因为我不断获得这个错误:
Fatal error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 3 bytes)
顺便说一下,我不明白3个字节是如何耗尽512M的...所以,如果那是我可以改变的东西,那就太好了,尽管如此,批量生产仍然可能更好?
答案 0 :(得分:6)
最后3个字节是打破骆驼背部的稻草。可能是在长串分配中导致失败的分配尝试。
不幸的是,libpq
会在放弃对应用程序的控制之前尝试在内存中完全缓存结果集。这是您在$myArray
中消耗的任何内存的补充。
建议使用 LIMIT ... OFFSET ...
来减少内存占用;这个会起作用,但效率很低,因为每次使用不同的偏移量重新发出查询时,可以不必要地复制服务器端排序工作(例如,为了回答{{1 Postgres仍然需要对整个结果集进行排序,只返回10000..10010行。)
相反,使用DECLARE ... CURSOR
创建服务器端游标,然后使用FETCH FORWARD x
来获取下一个LIMIT 10 OFFSET 10000
行。根据需要重复多次,或直到返回少于x
行。完成后不要忘记CLOSE
光标,即使/如果异常上升。
此外,不x
;如果您只需要SELECT *
和id
,请创建光标name
(否则FOR SELECT id, name
将不必要地检索和缓存您从未使用过的列,从而增加内存占用和整体查询时间。)
如上所述使用游标,libpq
任何时候都会在内存中保留最多libpq
行。但是,请确保尽可能在x
之间清除$myArray
,否则您仍可能因FETCH
而内存不足。
答案 1 :(得分:3)
您可以使用LIMIT (x)
和OFFSET (y)
答案 2 :(得分:0)
PostgreSQL服务器缓存查询结果,直到您实际检索它们为止,因此在这样的循环中将它们添加到数组中将导致内存耗尽,无论如何。要么一次处理一行结果,要么检查数组的长度,处理到目前为止拉出的结果,然后清除数组。
答案 3 :(得分:0)
错误意味着PHP正在尝试分配3个字节,但512MB的所有可用部分都少于3个字节。
即使您分批进行,依赖于生成的数组的大小,您仍然可以耗尽可用内存。
也许你真的不需要获得所有记录?