【问题标题】:PHP General Principles: is one big SQL call better or lots of little onesPHP 一般原则:一个大的 SQL 调用更好还是很多小的 SQL 调用更好
【发布时间】:2014-07-10 09:54:03
【问题描述】:

这是一个优化问题 RE:第一原则.. 想象一下我正在做一个大的繁重比较.. 30k 文件与 30k 数据库条目.. 将一个大 MySQL 放入一个数组然后循环遍历物理是最有效的吗?文件检查与数组还是更好地循环文件然后一次执行一行 MySQL 调用..

这里有一些伪代码来帮助解释:

 //is this faster?
 foreach($recursiveFileList as $fullpath){
     $Record = $db->queryrow("SELECT * FROM files WHERE fullpath='".$fullpath."'");
     //do some $Record logic           
 }


 //or is this faster
 $BigList = array();
 $db->query("SELECT * FROM files");
 while($Record = $db->rows()){
     $BigList[$Record['fullpath']] = $Record;
 }

 foreach($recursiveFileList as $fullpath){
     if (isset($BigList[$fullpath])){
         $Record = $BigList[$fullpath];
         //do some $Record logic
     }   
 }

【问题讨论】:

  • 您的 SQL 服务器与文件服务器不同吗?如果不是,那也没关系 tbh.MySQL 仍在使用文件将这些数据存储在您的服务器上,它只是为您提供了一个接口来推断所述数据。这主要只是一个微优化。
  • 这是一个本地数据库 - 一个 LAMP 服务器,也没有存储在 MySQL 中的文件 - 纯粹的路径名
  • 那真的没什么区别。如果您愿意,您可以连接第二台计算机并将其作为您的 SQL 服务器,然后您可以将大量处理卸载到 SQL 服务器上,这将有助于降低开销。但是,就目前而言,这将是最小的性能提升。
  • 你为什么不试试呢? stackoverflow.com/questions/6245971/…
  • 你这里用什么接口连接MySQL?您没有使用占位符,这通常表明您做错了事,并使自己面临严重的SQL injection bugs 风险。

标签: php mysql optimization lamp


【解决方案1】:

更新:如果您始终知道您的 $recursiveFileList 是表的 100%,那么每行执行一次查询将是不必要的开销。在这种情况下,只需使用SELECT * FROM files。

我不会使用您展示的两种样式中的任何一种。

第一种样式为每个单独的完整路径运行一个单独的 SQL 查询。这会导致一些 SQL 解析、优化等开销。请记住,MySQL 没有能力记住从类似查询的一次调用到下一次的查询优化。它每次都分析并执行查询优化。开销相对较小,但会增加。

第二种样式显示从表中获取所有行,并在应用程序层对其进行排序。这会产生 很多 开销,因为通常您的 $recursiveFileList 可能仅匹配表中行的 1% 或 0.1% 甚至更小的部分。我已经看到通过网络传输大量数据实际上耗尽了 1Gbps 网络交换机的情况,这为应用程序的每秒请求设置了上限。

明智地使用查询条件和索引,让 RDBMS 检查并仅返回匹配的行。

您展示的两种样式并不是唯一的选择。我的建议是使用 range 查询来匹配单个查询中的多个文件 fullpath 值。

$sql = "SELECT * FROM files WHERE fullpath IN (" 
    . array_fill(0, count($recursiveFileList), "?") . ")";
$stmt = $pdo->prepare($sql);
$stmt->execute($recursiveFileList);
while ($row = $stmt->fetch()) {
    //do some $Record logic           
}

注意,我还使用带有? 参数占位符的准备查询,然后在调用execute() 时分别传递完整路径值的数组。 PDO 非常适合这一点,因为您可以只传递一个数组,并且数组元素与参数占位符匹配。

这也解决了这种情况下SQL注入的风险。

【讨论】:

  • 谢谢,我完全理解indexes 的角色,但是第三种方式(我曾经想到的)不会与max_allowed_packet 发生冲突。同样,讨论注射风险是过时的。
  • 同样,匹配的可能性约为 100%,它是 MySQL files 表中所有内容的 $recursiveFileList - OP 试图说明这一点 - 30k 与 30k
  • 好的,我会在上面添加一些内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-16
  • 1970-01-01
  • 2016-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多