2011-06-10 24 views
3

我正在更新/修改某些數據庫代碼,我想知道,我應該用什麼真的期望使用預準備語句。MySQL準備好的語句與普通查詢。收益和損失

拿這個例子代碼:
(裸着我,我知道這是醜陋的 - 我自己寫的)

$values = ''; 
for ($i = 0; $i < $count; $i++) { 
    $name = mysql_real_escape_string ($list[$i][1]); 
    $voc = mysql_real_escape_string ($list[$i][3]); 
    $lev = $list[$it][2]; 
    $lev = is_numeric ($lev)? $lev : 0; 

    $values .= ($values == '')? "('$name', '$voc', $lev)" : ", ('$name', '$voc', $lev)"; 
} 
if ($values != '') { 
    $core->query ("INSERT INTO onlineCList (name, voc, lev) VALUES $values;"); 
} 

現在,除了在可讀性明顯的增益(,理智)和事實max_packet_size停止成爲一個問題,當我重新編碼以使用預準備語句時,我是否應該預期性能有任何變化?我正在遠程連接到MySQL服務器,我擔心發送多個小數據包會比發送一個大數據包慢得多。如果是這樣的話,MySQLi/mysqlnd可以緩存這些數據包嗎?

又如:

$names = ''; 
while ($row = mysql_fetch_array ($result, MYSQL_ASSOC)) { 
    $name = mysql_real_escape_string($row['name']); 

    $names .= ($names == '') ? "'$name'" : ", '$name'"; 
} 
if ($names != '') { 
    $core->query ("UPDATE onlineActivity SET online = NULL WHERE name IN ($names) AND online = 1;"); 
} 

如上所述,我應該期待意外,這重新編碼使用準備好的發言後?如果MySQL服務器必須運行一個帶有大IN子句的查詢,或者使用相等檢查(.. WHERE name = $name AND ..)運行多個準備好的查詢,它會對MySQL服務器有什麼影響嗎?

假設一切都正確索引。

+0

可能的重複[在PHP PERFORMANCE-WISE中應該使用MySQL語句嗎?](http:// stackoverflow.com/questions/2214408/should-i-use-prepared-statements-for-mysql-in-php-performance-wise) – e4c5 2016-04-24 02:14:34

回答

7

通常情況下,如果你只是代替普通的查詢使用準備好的語句,因爲查詢準備分兩步執行它或多或少地更慢而不是一個。準備好的陳述只有在準備陳述並多次執行時纔會變得更快。

但是,在這種情況下,您使用的是mysql_real_escape_string,它會往返數據庫。更糟糕的是,你正在循環內執行它,因此,執行多次每個查詢。因此,在這種情況下,用一個準備好的聲明取代所有這些往返行程是一種雙贏。

關於你的最後一個問題,沒有理由不能像使用普通查詢解析器那樣對準備好的語句使用相同的查詢(即沒有理由使用IN執行一個版本,而使用一堆OR值)。 prepared statement可以有IN (?, ?, ?),然後你只需綁定這些參數。

我的建議是總是使用準備好的語句。在他們增加邊際性能開銷的情況下,它們對於安全性(無SQL注入)和可讀性好處仍然值得。當然,任何時候你發現自己求助於mysql_real_escape_string,你應該使用準備好的語句。 (對於簡單的一次性查詢,在不需要跳過變量輸入的情況下,它們不是必須的。)

+0

謝謝,我不知道'mysql_real_escape_string'實際上與服務器通信時調用;我只是假定當你打開一個連接時存儲字符編碼,'mysql_real_escape_string'在本地工作,使用存儲的信息。 – OpiF 2011-06-10 04:02:46

+3

是的,它應該在PHP文檔中更加突出,它可以做到這一點。字節流被髮送到MySQL,使用其字符集設置轉義並返回轉義字符串...如果打開MySQL服務器的查詢日誌,您將看到所有這些「查詢」。有一箇舊的[mysql_escape_string](http://php.net/manual/en/function.mysql-escape-string.php)可以在本地使用,但它不尊重字符集,因此不推薦使用。如果你仔細想想,這是有道理的,只有MySQL可以使用其精確的字符集實現來轉義字符串數據。而是準備好的陳述的一個明顯例子。 – joelhardi 2011-06-10 04:30:41

+0

@joelhardi您對'mysql_real_escape_string'的評論非常有趣。這是否也適用於mysqli對象?有沒有任何基準顯示開銷是多少?我一直認爲使用預先準備好的語句,只要你一次計劃執行一次查詢是沒有意義的,所以有興趣知道你需要運行多少個real_escape_strings,而執行一次準備好的語句才能使後者更高效。我猜這是微型優化,但對所有相同的感興趣。 – texelate 2016-11-23 07:48:58

1
  1. 準備好的語句更安全。
  2. 準備好的語句具有更好的性能。
  3. 編寫的語句編寫起來更方便。

你會讀所有這些!

http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html

試試這個太

Prepared Statement vs. Stored Procedure

+3

2.取決於上下文。這是你的意見。 – texelate 2016-11-23 07:45:20

+1

準備好的語句非常好(特別是如果你有像用戶輸入一樣的安全問題),texelate是完全正確的,並且忘記提及它們讀取/調試的方便性。就我個人而言,我很少操縱用戶輸入,儘可能避免準備查詢,通常是因爲在需要修復失敗的請求時,如果沒有其實際的SQL內容,它不會帶來更大的麻煩。他們仍然很棒,但有*也有*理由不使用它們:) – Balmipour 2017-07-04 16:44:20