之前都是使用同事封装好的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);
}
一下子激起了我的好奇心,这俩参数到底有什么区别呢?做个测试先。
$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大呢?它节省的内存开销与带来的网络开销占比究竟如何,还需具体的测试数据来分析。
这两个参数背后的实际情况究竟怎样,还需要各路大神指点啊。