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 ... urlSELECT ... 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 性能不佳的主要内容,如果未能解决你的问题,请参考以下文章

性能不佳的 SQL 查询

SQL Server 查询性能不佳

PHP/xdebug profiler require_once 性能不佳

为啥使用 EF / Linq to sql 创建性能不佳的查询如此容易[关闭]

如何纠正 T-SQL 视图中的性能不佳

CTE 中的 SQL Server 视图导致性能不佳