PHP 80k 行的数组优化
PHP array optimization for 80k rows
我需要帮助找到克服 memory_limit 的解决方法。我的限制是 128MB,从数据库中我得到大约 80k 行,脚本停止在 66k。感谢您的帮助。
代码:
$posibilities = [];
foreach ($result as $item) {
$domainWord = str_replace("." . $item->tld, "", $item->address);
for ($i = 0; $i + 2 < strlen($domainWord); $i++) {
$tri = $domainWord[$i] . $domainWord[$i + 1] . $domainWord[$i + 2];
if (array_key_exists($tri, $possibilities)) {
$possibilities[$tri] += 1;
} else {
$possibilities[$tri] = 1;
}
}
}
鉴于您提供的微小(非常无用)代码片段,我想为您提供一个 MySQL 答案,但我不确定您使用的是 MySQL?
但是
- 优化你的 table.
使用 EXPLAIN
优化您的查询。重写您的查询,将尽可能多的逻辑放在查询中,而不是放在 PHP 代码中。
编辑:如果您使用的是 MySQL,则在 SELECT
关键字之前添加 EXPLAIN
,结果将向您解释您提供的查询 MySQL 实际如何变成结果.
不要使用 PHP strlen
函数,因为这是内存效率低下的 - 相反,您可以通过将字符串视为一组数组值来进行比较,因此:
for ($i = 0; !empty($domainWord[$i+2]); $i++) {
在您的 MySQL 中(如果您正在使用它)然后添加一个 LIMIT
子句,将查询分成 3 或 4 个块,比如 25k 行每个块,这将很适合您 66k 行的最大操作容量。 Burki 有这个好主意。
在每个块的末尾清理所有字符串并重新启动,设置为循环
$z = 0;
while ($z < 4){
///do grab of data from database. Preserve only your output
$z++;
}
但可能比这些更重要的是在您的问题中提供足够的细节!!
- 你想得到什么数据?
- 您将数据存储在什么地方?
- 查找数据的标准是什么?
这些答案将帮助比我知识渊博的人向您展示如何正确优化您的数据库。
根据您的算法,您的瓶颈很可能不是数据库查询,而是您正在构建的 $possibilities
数组。
如果我没看错你的代码,你会从数据库中得到一个域名列表。从每个域名中,您首先从末尾剥离顶级域。
然后从结果字符串的左到右逐个字符地遍历并从该字符串中收集字符的三元组,如下所示:
example.com
=> ['exa', 'xam', 'amp', 'mpl', 'ple']
你将这些三元组存储在数组的 keys
中,这是个好主意,你还对它们进行计数,这对内存消耗没有任何影响。然而,我的猜测是可能的三元组的绝对数量,即 26 个字母和 10 个数字是 36^3 = 46656 种可能性,每种只为数组中的 key 占用 3 个字节,不要不知道它周围有多少样板代码,从你的内存限制中拿走很多。
可能有人会告诉您 PHP 如何通过其数据库游标使用内存,我不知道,但您可以通过一种技巧来分析您的内存消耗。
拨打 memory-get-usage
:
- 在每次迭代之前和之后,这样您就会知道每次游标前进时浪费了多少内存,
- 每次加法前后
$possibilities
。
并立即打印出来。因此,您将能够 运行 您的代码并实时查看哪些内容以及使用内存的严重程度。
此外,尝试在每次迭代后 unset
$item
。它可能真的有帮助。
您用来获取$result
迭代器的特定数据库访问库的知识将有很大帮助。
我需要帮助找到克服 memory_limit 的解决方法。我的限制是 128MB,从数据库中我得到大约 80k 行,脚本停止在 66k。感谢您的帮助。
代码:
$posibilities = [];
foreach ($result as $item) {
$domainWord = str_replace("." . $item->tld, "", $item->address);
for ($i = 0; $i + 2 < strlen($domainWord); $i++) {
$tri = $domainWord[$i] . $domainWord[$i + 1] . $domainWord[$i + 2];
if (array_key_exists($tri, $possibilities)) {
$possibilities[$tri] += 1;
} else {
$possibilities[$tri] = 1;
}
}
}
鉴于您提供的微小(非常无用)代码片段,我想为您提供一个 MySQL 答案,但我不确定您使用的是 MySQL?
但是 - 优化你的 table.
使用
EXPLAIN
优化您的查询。重写您的查询,将尽可能多的逻辑放在查询中,而不是放在 PHP 代码中。 编辑:如果您使用的是 MySQL,则在SELECT
关键字之前添加EXPLAIN
,结果将向您解释您提供的查询 MySQL 实际如何变成结果.不要使用 PHP
strlen
函数,因为这是内存效率低下的 - 相反,您可以通过将字符串视为一组数组值来进行比较,因此:for ($i = 0; !empty($domainWord[$i+2]); $i++) {
在您的 MySQL 中(如果您正在使用它)然后添加一个
LIMIT
子句,将查询分成 3 或 4 个块,比如 25k 行每个块,这将很适合您 66k 行的最大操作容量。 Burki 有这个好主意。
在每个块的末尾清理所有字符串并重新启动,设置为循环
$z = 0;
while ($z < 4){
///do grab of data from database. Preserve only your output
$z++;
}
但可能比这些更重要的是在您的问题中提供足够的细节!! - 你想得到什么数据? - 您将数据存储在什么地方? - 查找数据的标准是什么?
这些答案将帮助比我知识渊博的人向您展示如何正确优化您的数据库。
根据您的算法,您的瓶颈很可能不是数据库查询,而是您正在构建的 $possibilities
数组。
如果我没看错你的代码,你会从数据库中得到一个域名列表。从每个域名中,您首先从末尾剥离顶级域。
然后从结果字符串的左到右逐个字符地遍历并从该字符串中收集字符的三元组,如下所示:
example.com
=> ['exa', 'xam', 'amp', 'mpl', 'ple']
你将这些三元组存储在数组的 keys
中,这是个好主意,你还对它们进行计数,这对内存消耗没有任何影响。然而,我的猜测是可能的三元组的绝对数量,即 26 个字母和 10 个数字是 36^3 = 46656 种可能性,每种只为数组中的 key 占用 3 个字节,不要不知道它周围有多少样板代码,从你的内存限制中拿走很多。
可能有人会告诉您 PHP 如何通过其数据库游标使用内存,我不知道,但您可以通过一种技巧来分析您的内存消耗。
拨打 memory-get-usage
:
- 在每次迭代之前和之后,这样您就会知道每次游标前进时浪费了多少内存,
- 每次加法前后
$possibilities
。
并立即打印出来。因此,您将能够 运行 您的代码并实时查看哪些内容以及使用内存的严重程度。
此外,尝试在每次迭代后 unset
$item
。它可能真的有帮助。
您用来获取$result
迭代器的特定数据库访问库的知识将有很大帮助。