ath=/services/php/etc' '--with-pdo-mysql=mysqlnd' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--enable-bcmath' '--enable-fpm
有点乱:
mysql、mysqli、pdo-mysql、libmysql、mysqlnd 好多名词,有点乱,没关系,一张图让你清晰起来:
mysql、mysqli、pdo-mysql、libmysql、mysqlnd之间关系
mysqlnd跟libmysql一样,都是直接与mysql server通讯的驱动类库。 而php程序员使用的mysql、mysqli、pdo-mysql是面向程序员调用的API接口。。
继续:
libmysql类库是MYSQL官方提供的类库,每次PHP编译都是指定参数来确定mysql\mysqli\pdo-mysql所使用的连接驱动是哪个。并且,前提你的得先装好mysql的客户端(libmysql类库),以确保有libmysqlclient.so ,
末学抱着试试看的心态,心情沉重的打开了libmysql的源码,终于在Safemalloc.c的line:120附近找到类似libmysqlclient申请内存的代码
//libmysql客户端库Safemalloc.c line:120
/* Allocate some memory. */
void *_mymalloc(size_t size, const char *filename, uint lineno, myf MyFlags)
{
...
/*
Test for memory limit overrun.
If compiled with DBUG, test for error injection. Described in my_sys.h.
*/
if ((size + sf_malloc_cur_memory > sf_malloc_mem_limit)
IF_DBUG(|| my_malloc_error_inject))
{
IF_DBUG(if (my_malloc_error_inject)
errno= ENOMEM;
my_malloc_error_inject= 0);
irem= 0;
}
else
{
/* Allocate the physical memory */
irem= (struct st_irem *) malloc (ALIGN_SIZE(sizeof(struct st_irem)) +
sf_malloc_prehunc +
size + /* size requested */
4 + /* overrun mark */
sf_malloc_endhunc); //系统的内存分配函数 malloc
}
...
}
//下面是mysqlnd驱动的代码,为了省的再弄一个代码高亮的区块,特意放一起了.
// Mysqlnd客户端库Mysqlnd_alloc.c line:77
/* {{{ _mysqlnd_emalloc */
void * _mysqlnd_emalloc(size_t size MYSQLND_MEM_D)
{
...
ret = _emalloc(REAL_SIZE(size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_ORIG_RELAY_CC); //调用zend的内存分配函数 _emalloc
...
if (ret && collect_memory_statistics) {
*(size_t *) ret = size;
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_MEM_EMALLOC_COUNT, 1, STAT_MEM_EMALLOC_AMOUNT, size);
}
TRACE_ALLOC_RETURN(FAKE_PTR(ret));
}
/* }}} */
也就是说,libmysql没有调用zend的内分分配函数_emalloc,就没法将内存的使用情况记录到mm_heap结构体中,也就是PHP的memory_get_usage()函数统计不到的原因。好了,虽然末学不是很能读懂源码,但似乎符合问题发生的现象了。
好像,末学又想到一个问题,如果libmysql保存的结果集所占用的内存的话,那么php的配置文件中的memory_limit也就无法限制他的内存使用情况了?也就是说,如果我们很理想的根据系统剩余内存分配了若干个php-fpm进程来启动运行的话,如果发生这情况,将会出现内存不够用的情况,libmysql占用的内存没有被统计到。。。结果是显然的,果然限制不了它。
libmysql与mysqlnd跟memory_limit之间的关系
那mysqlnd可以吗?mysqlnd的内存分配是使用zend的_emalloc函数吗?是的,没错mysqlnd 是我们的大救星。Mysqlnd_alloc.c line:77里代码中,明确看到了。各位SA在编译php时,一定要使用mysqlnd作为php连接mysql server的类库驱动哦。
Mysqlnd的好处可不止这么一点点啊。
内存还是内存:
末学苦于薄弱的英语,冒死翻过GFW,终于在“万恶的资本主义”国家的网站上找到了这些资料,mysqlnd将比libmysql节省将近40%的内存占用哦。如图:
mysqlnd比libmysql节省40%的内存占用
,而且,
memory_limit参数可以管的了它哦…
速度,速度:
国外友人给了一份测试结果,比较的API是mysql\mysqli,比较的驱动是libmysql\mysqlnd
- 使用mysqlnd驱动的ext\mysqli接口速度最快
- 使用libmysql驱动的ext\mysqli接口慢了6%
- 使用libmysql驱动的ext\mysql接口慢了3%
并且给出了mysqli在两个驱动下的执行时间:
mysqli_select_varchar_buffered
还有,还有哦…
mysqlnd还支持各种debug调试哦,各种strace跟踪哦…还支持….算了,你自己下载mysqlnd相比libmysql的优点看吧。末学可是搜了很久才搜到这个ppt。
推荐:
1,再推荐一片关于mysqlnd持久链接的文章:PHP 5.3: Persistent Connections with ext/mysqli
2,你的应用的cache的存储是程序员自己根据DB数据结果,查询条件,hash取值,存到memcache中的吗?想不想尝试下自动实现的?mysqlnd的插件可以尝试下:PHP: Client side caching for all MySQL extensions ,支持memcached,apc,sqlit哦。
回到开始:
有人说,当php调用mysql_query时,mysql server会返回本次查询的结果到php所在服务器的缓冲区中。当程序调用mysql_fetch_assoc/mysql_fetch_ro