为什么 PHP 使用大量内存来存储查询结果
Why is PHP using a lot of memory to store a query result
我使用 Laravel 8
直接使用 query builder
对 MySQL 8
table 执行查询以避免 Eloquent
开销,但我得到了无论如何都会消耗大量内存。
为了向您展示一个示例,我对 select 恰好 300 000 个元素执行以下查询。
我的代码如下所示:
$before = memory_get_usage();
$q_coords = DB::table('coords')->selectRaw('alt, lat, lng, id')
->where('active', 1)->take(300000)->get();
$after = memory_get_usage();
echo ($after - $before);
它显示 169760384 意思是 169MB 如果我没记错的话..
对我来说看起来很像,因为在我的查询中我只要求 2 float 和 2 bigInt,它们代表 4 x 8 字节(32字节).
并且.. 32 x 300 000 条记录 ~= 9600000(几乎 10MB)。
它怎么可能占用这么多内存?我很惊讶。
编辑
我也试过直接用PDO
,结果一样。
$query = DB::connection()->getPdo()->query("select alt, lat, lng, id from coords WHERE active = 1 LIMIT 300000");
$q_coords = $query->fetchAll();
因为它们在内存中表示为 PHP 个对象,而不仅仅是它们的原始数据使用。
但是有一个限制内存使用的解决方案:chunk
https://blackdeerdev.com/laravel-chunk-vs-cursor/
Chunk: It will “paginate” your query, this way you use less memory.
由于 Laravel Query Builder 使用 stdObj
来表示它的结果,您将有很多开销:
每个对象将存储行本身的值,以及每列的名称。所以你的32字节变成了很多字节。
在 PHP 中,每个变量都使用特定的数据结构进行处理,以允许 dynamic typing
、garbage collection
等..
你可以在这里看到一篇(很旧但还可以)文章:link
你还可以看到数组有更具体的处理,因为它需要一个桶,例如存储被视为字符串的数组键。
所有这些意味着(根据文章)大约有 144 字节的数据用于存储数组的元素。
好吧,虽然我不能完全解释你的结果,但我仍然可以告诉你,在你的情况下有这样的事情:
300 000 * 144 * 4 = 172 800 000
这意味着 300000 行 的 4 个变量 和 144 字节 变量。
如您所见,即使我的数学没有考虑 PHP 7 中的改进和其他因素,它与您得到的结果相差并不远...
我使用 Laravel 8
直接使用 query builder
对 MySQL 8
table 执行查询以避免 Eloquent
开销,但我得到了无论如何都会消耗大量内存。
为了向您展示一个示例,我对 select 恰好 300 000 个元素执行以下查询。
我的代码如下所示:
$before = memory_get_usage();
$q_coords = DB::table('coords')->selectRaw('alt, lat, lng, id')
->where('active', 1)->take(300000)->get();
$after = memory_get_usage();
echo ($after - $before);
它显示 169760384 意思是 169MB 如果我没记错的话..
对我来说看起来很像,因为在我的查询中我只要求 2 float 和 2 bigInt,它们代表 4 x 8 字节(32字节).
并且.. 32 x 300 000 条记录 ~= 9600000(几乎 10MB)。
它怎么可能占用这么多内存?我很惊讶。
编辑
我也试过直接用PDO
,结果一样。
$query = DB::connection()->getPdo()->query("select alt, lat, lng, id from coords WHERE active = 1 LIMIT 300000");
$q_coords = $query->fetchAll();
因为它们在内存中表示为 PHP 个对象,而不仅仅是它们的原始数据使用。 但是有一个限制内存使用的解决方案:chunk
https://blackdeerdev.com/laravel-chunk-vs-cursor/
Chunk: It will “paginate” your query, this way you use less memory.
由于 Laravel Query Builder 使用 stdObj
来表示它的结果,您将有很多开销:
每个对象将存储行本身的值,以及每列的名称。所以你的32字节变成了很多字节。
在 PHP 中,每个变量都使用特定的数据结构进行处理,以允许 dynamic typing
、garbage collection
等..
你可以在这里看到一篇(很旧但还可以)文章:link
你还可以看到数组有更具体的处理,因为它需要一个桶,例如存储被视为字符串的数组键。
所有这些意味着(根据文章)大约有 144 字节的数据用于存储数组的元素。
好吧,虽然我不能完全解释你的结果,但我仍然可以告诉你,在你的情况下有这样的事情:
300 000 * 144 * 4 = 172 800 000
这意味着 300000 行 的 4 个变量 和 144 字节 变量。
如您所见,即使我的数学没有考虑 PHP 7 中的改进和其他因素,它与您得到的结果相差并不远...