唯有前进值得敬仰

---等得越久,相聚时越幸福
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

mysql中的MYSQLI_USE_RESULT和MYSQLI_STORE_RESULT模式分析

Posted on 2013-04-24 19:25  绿豆芽33  阅读(3561)  评论(2编辑  收藏  举报

之前都是使用同事封装好的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大呢?它节省的内存开销与带来的网络开销占比究竟如何,还需具体的测试数据来分析。

这两个参数背后的实际情况究竟怎样,还需要各路大神指点啊。