PHP 通用原则 : is one big SQL call better or lots of little ones

标签 php mysql optimization lamp

这是一个优化问题 RE:第一原则..想象一下我正在做一个繁重的比较..30k 文件 vs 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
     }   
 }

最佳答案

Update: if you always know that your $recursiveFileList is 100% of the table, then doing one query per row would be needless overhead. In that case, just use 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 注入(inject)风险。

关于PHP 通用原则 : is one big SQL call better or lots of little ones,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23788556/

相关文章:

c - 查找在 C 中最常输入的数字的最佳(最快)方法?

java - 链接两个对象并逐个获取它们

php - 从 Analytics 中隐藏 Javascript 文件

javascript - PHP TCP连接时间延迟

php - 也使用多列过滤表mysql

php正则表达式最小和最大长度无法按预期工作

mysql - 联合两个表并重命名表特定列

javascript - 如何使用jquery从两个输入中获取值

Mysql: my.cnf 修改不生效

mysql - 如何删除mysql中的子分区