2013-03-13 44 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; 
}