PDO->prepare() bind vs sprintf() difference in performance
最近在做與資料庫有關的東西, 為了使 SQL 語句美觀可讀, 所以希望將語句與變數分開寫, 而不是直接拼成一個字元串.
PHP 里有兩種比較簡單的實現方法: 用 PDO 或其它類庫提供的預處理函數綁定變數; 或者用格式化字元串的函數 vsprintf() / sprintf() 處理.
本來想 Google 一下二者的性能差異, 結果 Stack Overflow 上居然沒人討論過, 於是自己測試了一下.
1.
$sql = new PDO(mysql:balabala);nn$state = ;n$param = [];nfor($i = 0; $i < 30000; ++ $i) {n $state .= n INSERT tablen SET table.`column_1` = ?,n table.`column_2` = ?n ;;n $param = array_merge($param, [n value_1,n value_2,n ]);n}nn$sql->prepare($state)->execute($param);n
將 30000 條有待格式化的語句拼接成一個字元串, 並將這些語句所需的變數存進一個一維數組, 最後通過 prepare()->execute() 綁定變數並查詢. 用時如下:
15.692095994949n15.630060911179n15.150625944138n16.030143976212n15.356143951416n18.03054189682n17.217720985413n17.266310930252n16.444499015808n17.730359077454n
2.
$sql = new PDO(mysql:balabala);nn$state = ;n$param = [];nfor($i = 0; $i < 30000; ++ $i) {n $state .= n INSERT tablen SET table.`column_1` = "%s",n table.`column_2` = "%s"n ;;n $param = array_merge($param, [n value_1,n value_2,n ]);n}nn$sql->query(vsprintf($state, $param));n
過程與第一種一致, 區別在於最後使用 vsprintf() 格式化字元串, 再通過 query() 查詢.
17.125224113464n16.484893083572n16.754585981369n17.174664974213n16.763854026794n17.275769948959n16.80862402916n18.309125900269n17.161306858063n17.066431045532n
速度貌似比第一種慢了一丟丟, 不過差別不大.
3.
$sql = new PDO(mysql:balabala);nn$state = ;nfor($i = 0; $i < 30000; ++ $i) {n $state .= vsprintf(n INSERT tablen SET table.`column_1` = "%s",n table.`column_2` = "%s"n ;, [n value_1,n value_2,n ]);n}nn$sql->query($state);n
再試一下每次循環通過 vsprintf() 直接格式化字元串, 不再最後處理, 最後只通過 query() 查詢.
8.2746200561523n8.7131369113922n8.0337510108948n7.258749961853n7.058333158493n8.8596909046173n7.7941257953644n7.8908619880676n9.0065298080444n7.5366899967194n
速度直接快了一倍.
4.
$sql = new PDO(mysql:balabala);nn$state = ;nfor($i = 0; $i < 30000; ++ $i) {n $state .= sprintf(n INSERT tablen SET table.`column_1` = "%s",n table.`column_2` = "%s"n ;,n value_1,n value_2n );n}nn$sql->query($state);n
最後順便試一下在第三種的基礎上, 將 vsprintf() 換成 sprintf().
7.0037219524384n7.651113986969n7.4348628520966n7.3054690361023n10.954452037811n7.9271950721741n7.2161939144135n7.6246650218964n6.8968040943146n7.2924418449402n
速度貌似微妙地快了一丟丟.
所以綜合來看, 將語句先格式化好再拼起來, 比攢成一堆再格式化要快不少, 如果非要攢成一堆再格式化, 使用 PDO->prepare() 可能比 vsprintf() 快一點點 (然而這是什麼鬼需求).
推薦閱讀:
※教你怎麼用EXCEL練習SQL
※SQL 設計得爛嗎,諸如redis,nosql又該如何選擇?
※Sqli labs系列-less-5&6 報錯注入法(下)
※sql中為什麼select要放在from之前?
※win7如何安裝SQL資料庫2000?