PHP 循环 - SQL 性能不佳
Posted
技术标签:
【中文标题】PHP 循环 - SQL 性能不佳【英文标题】:PHP loop - poor SQL performance 【发布时间】:2015-07-20 05:19:14 【问题描述】:我正在循环 40 个关联数组:
array(
'key0' => value,
'url0' => value,
'tit0' => value,
'cdn0' => value,
'cdn1' => value,
'cdn2' => value,
)
我正在执行多个select
和一个可能 insert
查询。我尝试通过减少查询量来优化性能。
foreach($buf)
$sth1->execute();//SELECT * FROM metadata WHERE url = '$buf['url0']'
$sth2->execute();//SELECT * FROM metadata WHERE key = '$buf['key0']'
if(!$ret=$sth1->fetch(PDO::FETCH_ASSOC))
if($sth2->fetch(PDO::FETCH_ASSOC))
die( 'key duplicate - error' );
$data[ ] = $buf;
$sth3->execute();//INSERT INTO metadata ...
else
$data[ ] = $ret;
但这很慢(循环大约需要 4.2 秒)。我尝试通过删除查询使其更快。
foreach($buf)
$sth1->execute();//SELECT * FROM metadata WHERE url = '$buf['url0']' OR key = '$buf['key0']'
if(!$ret=$sth1->fetch(PDO::FETCH_ASSOC))
$sth3->execute();//INSERT INTO metadata ...
$data[ ] = $buf;
else
if($ret['key']==$generated_key)die('key duplicate - error');
$data[ ] = $ret;
由于某种原因,这使它变得更慢(5-6s)。因此,我一无所知。我怎样才能使它有一个合理的加载时间?我尝试将$sth2->execute
放在if(!$ret...)
语句中,但这也没有给我任何速度提升。
问题似乎不是INSERT
,因为大部分array
数据已经是IN
数据库。每当我在 phpmyAdmin 中运行查询时,它会在 0.0000000003 秒内完成,因此它必须与循环有关。
【问题讨论】:
我会尝试对所有插入使用一个事务。它改变了数据库必须做的工作量以及何时做。在您的foreach loop
之前启动“事务”并在之后关闭它。意识到。任何错误,那么所有 40 次插入都需要再次完成。
完成。速度略有增加。 (0.2 秒)。谢谢。
嗯...这令人失望。我会建议“解释计划”并安排查询时间以查看它在哪里花费时间。我还会考虑在“foreach”循环之前“准备”查询。
@RyanVincent 有些查询只需要做两次插入,所以问题不在于那里。准备它们已经在 foreach 循环之前完成
在循环内执行查询会大大降低您网站的性能。如果您需要获取数百行,那么您的循环将进行数百次查询。避免这种情况的一种方法是映射您的 where
凭据数组并在循环外使用 WHERE IN
执行单个查询。
【参考方案1】:
加速#1:将$sth2->execute();
移动到第一个if
之后。如果url
测试成功,您似乎不需要结果。
加速#2:确保拥有INDEX(url)
和INDEX(key)
;
加速#3:将INDEX(key)
更改为UNIQUE(key)
并跳过SELECT ... key
;只需在执行INSERT
后检查 dup 键即可。
加速#4:(这个可能有帮助也可能没有帮助。)在一个查询中完成所有SELECT ... url
:SELECT ... url IN (40-urls-in-list)
。 (需要 Speedup #2。)将结果保存在关联数组中并遍历它以执行其余的 SELECT/INSERT 工作。
加速 #5:构建一个“批处理”INSERT
(单个 INSERT
中的多行),然后在 40 项循环结束时创建execute
。
请提供SHOW CREATE TABLE
。
MyISAM?还是 InnoDB?您是否已将 innodb_buffer_pool_size 调整为可用 RAM 的 70% 左右?如果没有,这可能会提高性能。
【讨论】:
【参考方案2】:你认为有这种可能性吗? https://dev.mysql.com/doc/refman/5.0/en/insert-select.html
【讨论】:
如果您在此处添加一些解释并提供参考会有所帮助。 :)【参考方案3】:很遗憾,没有足够的信息来说明您的 MySQL 索引策略或您选择的信息量。
第一秒想到的可能问题:
当您从 MySQL 执行查询时,您会遇到查询缓存,循环缓存在某个时间点已过期 数据库中的索引策略不佳 - 通过 varchar 选择并不总是最好的解决方案,使用 char(16) 和 MD5 sum(或类似的东西)可能是更好的方法 迭代中有一些未被注意到的循环解决所有这些问题的方法是用精确的时间戳回显大量调试数据,读取它们并将 SQL 查询记录到 MySQL 服务器日志中,然后在控制台/PHPMyAdmin 中批量运行所有这些以进行更好的调试。
【讨论】:
以上是关于PHP 循环 - SQL 性能不佳的主要内容,如果未能解决你的问题,请参考以下文章
PHP/xdebug profiler require_once 性能不佳