【发布时间】:2016-12-01 14:00:16
【问题描述】:
我有大型 MySQL 查询(180 万行,25 列),我需要从中创建二维数组(基于主键的内存表)。
代码按预期工作,但在 PHP7.0 中创建 $table 需要很长时间。
PHP7.0性能差这么多的原因是什么?我的主要兴趣是 mysqli。
感谢您提供任何见解 - 如果我可以修复性能,PHP7 会为我节省大量内存。
mysqli代码sn-p
$start = microtime(true);
$vysledek = cluster::query("SELECT * FROM `table` WHERE 1");
$query_time = (microtime(true) - $start);
$start_fetch = microtime(true);
while($zaznam = mysqli_fetch_assoc ( $vysledek )){
$fetch_time+= (microtime(true) - $start_fetch);
$start_assign = microtime(true);
$table[$zaznam['prikey']] = $zaznam;
$assign_time+= (microtime(true) - $start_assign);
$start_fetch = microtime(true);
}
$total_time+= (microtime(true) - $start);
echo round($assign_time, 2).' seconds to set the array values\n';
echo round($query_time, 2).' seconds to execute the query\n';
echo round($fetch_time, 2).' seconds to fetch data\n';
echo round($total_time, 2).' seconds to execute whole script\n';
echo "Peak Memory Usage:".round(memory_get_peak_usage(true)/(1024 * 1024), 2)." MB\n";
mysqli 结果
Deb 7 PHP 5.4 mysqlnd 5.0.10
1.8 秒设置数组值
8.37 秒执行查询
13.49 秒获取数据
24.42 秒执行整个脚本
峰值内存使用:8426.75 MB
Deb 8 PHP 5.6 mysqlnd 5.0.11-dev
1.7 秒设置数组值
8.58 秒执行查询
12.55 秒获取数据
23.6 秒执行整个脚本
峰值内存使用:8426.75 MB
Deb 8 PHP 7.0 mysqlnd 5.0.12-dev
0.73 秒设置数组值
8.63 秒执行查询
126.71 秒获取数据
136.46 秒执行整个脚本
峰值内存使用:7394.27 MB
Deb 8 PHP 7.0 mysqlnd 5.0.12-dev 扩展基准测试
我已经扩展了部分获取的基准测试,以每 100k 行报告一次,结果如下:
在 1.87 秒内获取 100000 行
行在 5.24 秒内获取 300000
行在 10.97 秒内获取 500000
行数在 19.17 秒内获取 700000
行数在 29.96 秒内获取 900000
行在 43.03 秒内获取 1100000
行在 58.48 秒内获取 1300000
行在 76.47 秒内获取 1500000
行数在 96.73 秒内获取 1700000
在 107.78 秒内获取 1800000 行
DEB8 PHP7.1.0-dev libclient 5.5.50
1.56 秒设置数组值
8.38 秒执行查询
456.52 秒获取数据
467.68 秒执行整个脚本
峰值内存使用量:8916 MB
DEB8 PHP7.1.0-dev libclient 5.5.50 扩展基准测试
在 2.72 秒内获取 100000 行
行在 15.7 秒内获取 300000
行在 38.7 秒内获取 500000
行在 71.69 秒内获取 700000
行数在 114.8 秒内获取 900000
在 168.18 秒内获取 1100000 行
行数在 231.69 秒内获取 1300000
行在 305.36 秒内获取 1500000
在 389.05 秒内获取 1700000 行
行数在 434.71 秒内获取 1800000
DEB8 PHP7.1.0-dev mysqlnd 5.0.12-dev
1.51 秒设置数组值
9.16 秒执行查询
261.72 秒获取数据
273.61 秒执行整个脚本
峰值内存使用:8984.27 MB
DEB8 PHP7.1.0-dev mysqlnd 5.0.12-dev 扩展基准测试
在 3.3 秒内获取 100000 行
在 13.63 秒内获取 300000 行
行数在 29.02 秒内获取 500000
行数在 49.21 秒内获取 700000
行在 74.56 秒内获取 900000
行在 104.97 秒内获取 1100000
在 140.03 秒内获取 1300000 行
行在 180.42 秒内获取 1500000
行数在 225.72 秒内获取 1700000
行在 250.01 秒内获取 1800000
PDO 代码 sn-p
$start = microtime(true);
$sql = "SELECT * FROM `table` WHERE 1";
$vysledek = $dbh->query($sql, PDO::FETCH_ASSOC);
$query_time = (microtime(true) - $start);
$start_fetch = microtime(true);
foreach($vysledek as $zaznam){
$fetch_time+= (microtime(true) - $start_fetch);
$start_assign = microtime(true);
$table[$zaznam['prikey']] = $zaznam;
$assign_time+= (microtime(true) - $start_assign);
$start_fetch = microtime(true);
}
$total_time+= (microtime(true) - $start);
echo round($assign_time, 2).' seconds to set the array values\n';
echo round($query_time, 2).' seconds to execute the query\n';
echo round($fetch_time, 2).' seconds to fetch data\n';
echo round($total_time, 2).' seconds to execute whole script\n';
echo "Peak Memory Usage:".round(memory_get_peak_usage(true)/(1024 * 1024), 2)." MB\n";
PDO 结果
Deb 7 PHP 5.4 mysqlnd 5.0.10
1.85 秒设置数组值
12.51 秒执行查询
16.75 秒获取数据
31.82 秒执行整个脚本
峰值内存使用量:11417.5 MB
Deb 8 PHP 5.6 mysqlnd 5.0.11-dev
1.75 秒设置数组值
12.16 秒执行查询
15.72 秒获取数据
30.39 秒执行整个脚本
峰值内存使用:11417.75 MB
Deb 8 PHP 7.0 mysqlnd 5.0.12-dev
0.71 秒设置数组值
35.93 秒执行查询
114.16 秒获取数据
151.19 秒执行整个脚本
峰值内存使用量:6620.29 MB
基线比较代码
$start_query = microtime(true);
exec("mysql --user=foo --host=1.2.3.4 --password=bar -e'SELECT * FROM `profile`.`table`' > /tmp/out.csv");
$query_time = (microtime(true) - $start_query);
echo round($query_time, 2).' seconds to execute the query \n';
所有系统的执行时间都相似,都是 19 秒 +-1 秒的变化。
基于上述观察,我会说 PHP 5.X 是合理的,因为执行的工作比仅仅转储到文件要多。
- 所有 3 台服务器都在同一主机上(源服务器和两台测试服务器)
- 重复测试时保持一致
-
内存中已经有类似的变量了,需要做对比去掉测试,与问题无关 - CPU 一直处于 100% 的状态
- 两台服务器都有 32G RAM 和 swappiness 设置为 1,目标是将其作为内存操作执行
- 测试服务器是专用的,没有其他东西在运行
- php.ini 在主要版本之间发生了变化,但与 mysqli/PDO 相关的所有选项似乎都相同
Deb8机器降级到PHP5.6后问题消失,重装PHP7后恢复
在 php.net - ID 72736 报告了一个错误,因为我相信已经证明问题出在 PHP 而不是系统或任何其他配置中
编辑 1:添加 PDO 比较
编辑 2:添加基准标记,编辑 PDO 结果,因为存在基准错误
编辑 3:主要清理原始问题,重建代码片段以更好地指示错误
Edit 4 : PHP 降级和升级的补充点
编辑 5:为 DEB8 PHP7.0 添加了扩展基准测试
编辑 6:包含 php7 配置
Edit 7:使用两个库对 PHP 7.1 开发人员进行性能测量 - 使用 bishop 的配置编译,删除了我的 php-config
编辑 8:添加了与 CLI 命令的比较,小幅清理
【问题讨论】:
-
只是好奇:你用 PDO 也试过了吗?
-
实际上它非常高效,在 PHP5.4 中,您可以在 40 - 60 秒内比较来自 2 个不同数据库的 2 个这样的表。同时对数据库的操作是非阻塞的,您可以进行单独的插入/删除/更新,原始应用程序可以一直在这些表之上运行。另一点是您可以在不同的服务器上执行此操作,因此即使耗尽内存也不会杀死目标数据库。
-
php.ini文件中的所有 mysqli 设置在 PHP7 中是否与在 PHP5 中相同?您是否为两者都安装了 x86 或 x64?如果将 PHP5 放在 Debian8 上,是否存在相同的性能差异?您是否在两台服务器上使用相同的 MySQL 驱动程序? -
@MonkeyZeus php.ini 是相同的,服务器是(x64)并且只是克隆和升级,所以我可以使用 apt-get 来轻松安装 PHP7 ,其中 1 只是为了显示它的完整扫描- 可以省略,对查询没有影响
-
您使用的是
libmysqlclient还是mysqlnd? (来自php -i的configure命令会有所帮助。)引擎代码会根据此选择通过不同的路径。
标签: php mysql performance multidimensional-array mysqli