2013-03-13 18 views
1

以下代码是我真实代码的模型。当myFunction被调用时,我获得了很大的性能提升。 myTable不超过几百行,但调用myFunction会增加约10秒的执行时间。试图在已经访问该表的循环内访问表的一行时是否存在固有的错误?MySQL性能同时访问表

<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; 
+1

你意识到你查询'myTable' N + 1次,其中n是行权的数量? – tonyjmnz 2013-03-13 19:29:54

+0

当你看到在循环中选择,你知道某件事情正在做错 – 2013-03-13 19:34:33

+0

这就是我的问题:为什么不能myFunction,有它自己的局部变量和指针,独立于主例程访问myTable? – user2033684 2013-03-13 19:41:44

回答

2

你在做什么有时也被称为 “N + 1个查询” 的问题。您运行第一个(外部)查询1次,并返回N行。然后,运行N个从属查询,第一个查询返回的每个行都有一个查询。因此N + 1查询。它会导致很多开销。

这将有更好的表现,如果你能适用于SQL的“东西”条件:

$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查询模式。

+0

有意义。我已经在这里解决了类似于建议的问题,但这解释了为什么它发生了。谢谢。 – user2033684 2013-03-13 20:08:35

0

因此,如果表中有“几百行”,则可能会调用myFunction几百次,具体取决于第一个查询返回的行数。

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

之后,确保你有myTable.ID索引。

之后,我会开始研究系统/服务器级别的问题。在较慢的系统上,比如说一台笔记本电脑硬盘,每秒可能会有10个查询。

0

尝试这样:

$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; 
}