之前用 MySQL 的 C API 的时候,里面提到了获取查询结果的时候,有 2 个函数: 和 。其中的主要差别为 mysql_store_result() 是一次性的把所有的结果都读取到 Client 的内存里面的,而 mysql_use_result() 则只是读取一部分,需要 Client 不断的调用 来获取剩下的数据。
当时我就有个疑问:当 Client 发送 SQL 语句给 MySQL 服务端以后,服务端是怎么返回数据的,如果为 mysql_store_result(),那么应该是一次性的将所有结果都返回的。那么 mysql_use_result() 呢?是每次调用 mysql_fetch_row() 的时候,从服务端读取一点数据回来,还是其他方法?
如果采用 mysql_use_result(),mysql_fetch_row() 是每次从服务器读取一点数据的话,那么这个对性能应该是有比较明显的影响的,这样在开发的时候,对于到底是否采用 mysql_use_result() 还是 mysql_store_result() 有需要有更多的关心。
为了分析这个问题,我写了一个简单的小程序,然后采用 wireshark 来抓包。
验证下来:
1. 从协议上来看,mysql_real_query() 执行的时候,Client 端就将 SQL 发送给服务端了,服务端不会等待其他协议,很快就直接返回查询的结果。
2. 服务端返回的结果中,不会包含有多少条结果,所以最后有多少条结果,是由 Client 端自己算出来的。
3. 服务端一开始就会返回有多少个字段,每个字段的名称和属性。所以执行例如 mysql_fetch_field() 这样的函数是不会再向服务端发送请求的。
4. 服务端然后再返回每条记录的数据。这个时候 Client 有可能还没有执行 mysql_use_result() 或者 mysql_store_result() 的!也就是说,mysql_use_result() 和 mysql_store_result() 在协议层次上,是一样的协议。
5. 服务端数据发送完毕的时候,有特别的一个数据发送过来表明数据发送完毕了。
6. 那么 mysql_store_result() 的实现,应该是一直读取数据,直到读取完毕了为止。而 mysql_use_result(),则应该是一部分一部分的读取的,如果返回的数据超过了 TCP 的缓冲区大小,那么 MySQL 服务端的处理线程应该会堵塞在例如 write() 这样的函数上。
7. 放心的使用 mysql_use_result() 吧,性能还是很好的。
这几天学 Java,MySQL for JDBC 的驱动的代码中,好像没有明确区分出来 use or store 这样的方式,以后有空了再仔细看看。