MySQL性能影响同时访问表


MySQL performance hit accessing table simultaneously

下面的代码是我的真实代码的模型。当myFunction被调用时,我的性能受到了很大的影响。myTable不超过几百行,但是调用myFunction会增加大约10秒的执行时间。在已经访问该表的循环中访问表的一行是否存在固有的错误?

<select>
<?php
  $stmt = SQLout ("SELECT ID,Title FROM myTable WHERE LEFT(Title,2) = ? ORDER BY Title DESC",
                   array ('s', $co), array (&$id, &$co_title));
  while ($stmt->fetch()) {
    if (myFunction($id))  // skip this function call and save 10 seconds
      echo '<option value="' . $co_title . '">' . $co_title . '</option>';
  }
  $stmt->close();

function myFunction ($id) {
  $stmt = SQLout ("SELECT Info FROM myTable WHERE ID = ?",
                   array ('i', $id), array (&$info));
  if ($stmt->fetch()) {
    $stmt->close();
    if ($info == $something)
      return true;
  }
  return false;
}
?>

SQLout基本上是:

$sqli_db->prepare($query);
$stmt->bind_param;
$stmt->execute();
$stmt->bind_result;
return $stmt;

你所做的有时被称为"N+1查询"问题。您运行第一个(外部)查询1次,它返回N行。然后运行N个从属查询,每个查询对应第一个查询返回的行。因此有N+1个查询。这会导致大量的开销。

如果您可以在SQL中应用"something"条件,将会有更好的性能:

$stmt = SQLout ("SELECT ID,Title FROM myTable 
    WHERE LEFT(Title,2) = ? AND Info = ... ORDER BY Title DESC",
    array ('s', $co), array (&$id, &$co_title));

一般来说,在依赖于有多少行与外部查询匹配的循环中运行查询不是一个好主意。如果外部查询匹配1000000行怎么办?这意味着为了这个PHP请求,将在循环内对数据库进行一百万个查询。

即使今天外部查询只匹配3行,你以这种方式构建代码的事实意味着六个月后,在一些不可预测的时间,会有一些搜索导致巨大的开销,即使你的代码没有改变。查询的数量是由数据驱动的,而不是代码。

有时必须做你正在做的事情,例如"某事"条件很复杂,不能用SQL表达式表示。但是您应该在所有其他情况下尝试避免这种N+1查询模式。

所以,如果表中有"几百行",你可能会调用myFunction几百次,这取决于在第一个查询中返回了多少行。

检查第一个查询返回的行数,以确保它符合您的期望。

之后,确保在myTable.ID上有一个索引。

之后,我将开始研究系统/服务器级别的问题。在较慢的系统上,例如笔记本电脑硬盘,每秒10个查询可能是您所能得到的。

试试这样:

  $stmt = SQLout ("SELECT ID,Title, Info FROM myTable WHERE LEFT(Title,2) = ? ORDER BY Title DESC",
                   array ('s', $co), array (&$id, &$co_title, &$info));
  while ($stmt->fetch()) {
    if (myFunction($info))  // skip this function call and save 10 seconds
      echo '<option value="' . $co_title . '">' . $co_title . '</option>';
  }
  $stmt->close();
function myFunction ($info) {
  if ($info == $something)
    return true;
  }
  return false;
}