之前都是使用同事封裝好的mysql類,今天做性能測試時自己手動編寫了查詢mysql的操作。偶然發現mysqli::query(或者mysqli_query)有一個參數$resultmode取值為MYSQLI_USE_RESULT or MYSQLI_STORE_RESULT。平時封裝好的類中都是使用默認的MYSQLI_STORE_RESULT。Phpmanul上給出了這么一段話:
Either the constant MYSQLI_USE_RESULT or MYSQLI_STORE_RESULT depending on the desired behavior. By default, MYSQLI_STORE_RESULT is used.
If you use MYSQLI_USE_RESULT all subsequent calls will return error Commands out of sync unless you call mysqli_free_result().
下面又有人注釋了這樣一句:
/* If we have to retrieve large amount of data we use MYSQLI_USE_RESULT */
if ($result = mysqli_query($link, "SELECT * FROM City", MYSQLI_USE_RESULT)) {
/* Note, that we can't execute any functions which interact with the
server until result set was closed. All calls will return an
'out of sync' error */
if (!mysqli_query($link, "SET @a:='this will not work'")) {
printf("Error: %s\n", mysqli_error($link));
}
mysqli_free_result($result);
}
一下子激起了我的好奇心,這倆參數到底有什么區別呢?做個測試先。
<?php
$link = mysqli_connect("localhost", "userxx", "pwdxx", "dbtest");
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$quick = true;
$query_type = $quick ? MYSQLI_USE_RESULT : MYSQLI_STORE_RESULT;
$sql = "select * from tbl_xx";
$qrs = mysqli_query($link, $sql, $query_type);
/*先注釋掉這段
$sql_ex = "delete from tbl_xx where xx";
$ret = mysqli_query($link,$sql_ex);
if (!$ret)
{
printf("Error:%s\n",mysqli_error($link));
}
*/
var_dump($qrs);
$rows =array();
while(($row= mysqli_fetch_array($qrs, MYSQLI_ASSOC))!=null)
{
$rows[]=$row;
}
mysqli_free_result($qrs);
mysqli_close($link);
?>
我們用quick開關控制這倆參數的選擇;分別來看返回的結果集對象。
MYSQLI_USE_RESULT:
MYSQLI_STORE_RESULT:
看到沒有,果然有區別,使用MYSQLI_USE_RESULT時返回的結果集對象的num_rows為0,而使用MYSQLI_STORE_RESULT時返回的結果集對象的num_rows為本次查詢對應的實際行數。打開xdebug,再來看看執行時間:
上圖左邊使用MYSQLI_STORE_RESULT的兩次統計結果,右邊是使用MYSQLI_USE_RESULT的兩次統計結果。實際上應該執行n次按平均值做對比,這里就偷懶了,僅各執行了兩次。能夠看出,右邊的mysqli_fectch_array操作要比左邊的多出30%-60%的時間。
結合上面兩個統計結果,再google一通,這兩個參數的區別可以總結為:
MYSQLI_USE_RESULT和MYSQLI_STORE_RESULT決定了mysqli client和server之間取結果集的方式。前者查詢的時候並沒有從server將結果集取回,后者查詢時提取結果集返回給client,並分配內存,存儲到用戶程序空間中,之后mysqli_fetch_array()相當於是從本地取數據;而MYSQLI_USE_RESULT方式下,mysqli_fetch_array()每次都要向server請求結果行。
難怪phpmanual上那人注釋說當檢索大量數據時建議使用MYSQLI_USE_RESULT,因為MYSQLI_USE_RESULT有較低的內存需求,而MYSQLI_STORE_RESULT需要在client本地維護結果集,內存開銷大。說到這里,可能會想,MYSQLI_USE_RESULT每次取數據時都要請求server,網絡開銷是不是要比MYSQLI_STORE_RESULT大呢?它節省的內存開銷與帶來的網絡開銷占比究竟如何,還需具體的測試數據來分析。
這兩個參數背后的實際情況究竟怎樣,還需要各路大神指點啊。