PHP 循环 - SQL 性能不佳
PHP loop - poor SQL performance
我正在遍历 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-6 秒)。因此,我一无所知。我怎样才能让它有一个合理的加载时间?我尝试将 $sth2->execute
放在 if(!$ret...)
语句中,但这也没有给我任何速度增益。
似乎 INSERT
不是问题所在,因为大多数 array
数据已经 IN
数据库。每当我 运行 在 phpmyAdmin 中查询时,它都会在 0.0000000003 秒内完成,所以它一定与循环有关。
你认为有这种可能吗?
https://dev.mysql.com/doc/refman/5.0/en/insert-select.html
很遗憾,关于您的 MySQL 索引策略或您 select 的信息量不足。
第一秒想到的可能问题:
- 当您从 MySQL 执行查询时,您命中了查询缓存,来自循环缓存的内容在某个时候已过期
- 数据库中糟糕的索引策略 - selection by varchar 并不总是最好的解决方案,使用 char(16) 和 MD5 sum(或类似的东西)可能是更好的方法
- 你在迭代中有一些未被注意到的循环
所有这些的解决方案是回显大量带有精确时间戳的调试数据,阅读它们并将 SQL 查询记录到 MySQL 服务器日志和 运行 所有这些console/PHPMyAdmin 一批,以便更好地调试。
加速 #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:构建一个 'batch' INSERT
( 单个 INSERT
中的多行),然后 execute
它在 40 项循环的末尾。
请提供SHOW CREATE TABLE
.
MyISAM?还是InnoDB?您是否已将 innodb_buffer_pool_size 调整为大约可用 RAM 的 70%?如果不是,这可能会提高性能。
我正在遍历 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-6 秒)。因此,我一无所知。我怎样才能让它有一个合理的加载时间?我尝试将 $sth2->execute
放在 if(!$ret...)
语句中,但这也没有给我任何速度增益。
似乎 INSERT
不是问题所在,因为大多数 array
数据已经 IN
数据库。每当我 运行 在 phpmyAdmin 中查询时,它都会在 0.0000000003 秒内完成,所以它一定与循环有关。
你认为有这种可能吗? https://dev.mysql.com/doc/refman/5.0/en/insert-select.html
很遗憾,关于您的 MySQL 索引策略或您 select 的信息量不足。
第一秒想到的可能问题:
- 当您从 MySQL 执行查询时,您命中了查询缓存,来自循环缓存的内容在某个时候已过期
- 数据库中糟糕的索引策略 - selection by varchar 并不总是最好的解决方案,使用 char(16) 和 MD5 sum(或类似的东西)可能是更好的方法
- 你在迭代中有一些未被注意到的循环
所有这些的解决方案是回显大量带有精确时间戳的调试数据,阅读它们并将 SQL 查询记录到 MySQL 服务器日志和 运行 所有这些console/PHPMyAdmin 一批,以便更好地调试。
加速 #1:将 $sth2->execute();
移动到第一个 if
之后。如果 url
测试成功,您似乎不需要结果。
加速 #2:确保有 INDEX(url)
和 INDEX(key)
;
加速 #3:将 INDEX(key)
更改为 UNIQUE(key)
并跳过 SELECT ... key
;在执行 INSERT
.
加速 #4:(这个可能有帮助也可能没有帮助。)在单个查询中完成所有 SELECT ... url
:SELECT ... url IN (40-urls-in-list)
。 (需要 Speedup #2。)将结果保存在一个关联数组中并遍历它以完成其余的 SELECT/INSERT 事情。
加速 #5:构建一个 'batch' INSERT
( 单个 INSERT
中的多行),然后 execute
它在 40 项循环的末尾。
请提供SHOW CREATE TABLE
.
MyISAM?还是InnoDB?您是否已将 innodb_buffer_pool_size 调整为大约可用 RAM 的 70%?如果不是,这可能会提高性能。