PHP查詢(xún)MySQL海量數(shù)據(jù)內(nèi)存占用分析
  • 更新時(shí)間:2024-11-06 13:50:16
  • 網(wǎng)站建設(shè)
  • 發(fā)布時(shí)間:1年前
  • 475

PHP查詢(xún)MySQL大量數(shù)據(jù)的內(nèi)存占用分析

本文主要從原理、手冊(cè)和源碼分析PHP查詢(xún)MySQL時(shí)返回大量結(jié)果的內(nèi)存占用問(wèn)題,同時(shí)也涉及到MySQL C API的使用。

昨天有同事在PHP討論組提到,他在做的一個(gè)項(xiàng)目,MySQL查詢(xún)返回的結(jié)果太多(最多10萬(wàn)條),導(dǎo)致PHP內(nèi)存不足。于是,他問(wèn),執(zhí)行完下面的代碼遍歷返回MySQL結(jié)果之前,數(shù)據(jù)是否已經(jīng)在內(nèi)存中了? -

while($row=mysql_fetch_assoc($result)){

//.

}

當(dāng)然,針對(duì)這類(lèi)問(wèn)題的優(yōu)化方法有很多。不過(guò),就這個(gè)問(wèn)題,我首先想到的是MySQL是經(jīng)典的C/S(Client/Server,客戶(hù)端/服務(wù)器)模型。在遍歷結(jié)果集之前,底層實(shí)現(xiàn)可能已經(jīng)通過(guò)網(wǎng)絡(luò)(假設(shè)使用TCP/IP)將所有數(shù)據(jù)讀到客戶(hù)端緩沖區(qū),還有一種可能是數(shù)據(jù)還在服務(wù)端的發(fā)送緩沖區(qū)中,并且已經(jīng)沒(méi)有傳送給客戶(hù)端。

之前看PHP和MySQL的源碼,注意到PHP手冊(cè):中有兩個(gè)功能相似的函數(shù)

mysql_查詢(xún)()

mysql_unbuffered_query()

這兩個(gè)函數(shù)的字面意思和描述證實(shí)了我的想法。執(zhí)行前一個(gè)函數(shù)時(shí),會(huì)將服務(wù)器端的所有結(jié)果集讀取到客戶(hù)端緩沖區(qū),而后一個(gè)函數(shù)則不會(huì)。這就是“無(wú)緩沖(unbuffered)”的意思。

也就是說(shuō),如果使用mysql_unbuffered_query()執(zhí)行一個(gè)返回大結(jié)果集的SQL語(yǔ)句,在遍歷結(jié)果之前,PHP的內(nèi)存是不會(huì)被結(jié)果集占用的。如果用mysql_query()執(zhí)行同樣的語(yǔ)句,函數(shù)返回,PHP的內(nèi)存占用會(huì)急劇增加,內(nèi)存會(huì)馬上被耗盡。

如果你看過(guò)PHP的相關(guān)代碼,就可以看出這兩個(gè)函數(shù)實(shí)現(xiàn)的異同:

/*{{{protoresourcemysql_query(stringquery[,intlink_identifier])

向MySQL 發(fā)送SQL 查詢(xún)*/

PHP_FUNCTION(mysql_query)

{

php_mysql_do_query(INTERNAL_FUNCTION_PARAM_PASSTHRU,MYSQL_STORE_RESULT);

}

/*}}}*/

/*{{{protoresourcemysql_unbuffered_query(stringquery[,intlink_identifier])

向MySQL 發(fā)送SQL 查詢(xún),不獲取和緩沖結(jié)果行*/

PHP_FUNCTION(mysql_unbuffered_query)

{

php_mysql_do_query(INTERNAL_FUNCTION_PARAM_PASSTHRU,MYSQL_USE_RESULT);

}

/*}}}*/

兩個(gè)函數(shù)都調(diào)用了php_mysql_do_query(),只是第二個(gè)參數(shù)不同,MYSQL_STORE_RESULT和MYSQL_USE_RESULT。查看php_mysql_do_query()的實(shí)現(xiàn):

如果(使用存儲(chǔ)==MYSQL_USE_RESULT){

mysql_result=mysql_use_result(mysql-conn);

}別的{

mysql_result=mysql_store_result(mysql-conn);

}

mysql_use_result() 和mysql_store_result() 是MySQL C API 函數(shù)。這兩個(gè)C API函數(shù)的區(qū)別在于,后者是從MySQL Server讀取所有的結(jié)果集到Client,而前者只讀取結(jié)果集的元信息。

回到PHP,使用mysql_unbuffered_query() 來(lái)避免直接內(nèi)存占用。如果在遍歷過(guò)程中結(jié)果沒(méi)有被“PHP緩存”(比如放在一個(gè)數(shù)組中),雖然整個(gè)執(zhí)行過(guò)程操作了10萬(wàn)條或者百萬(wàn)條或者更多的數(shù)據(jù),但是PHP占用的內(nèi)存總是很小的。

標(biāo)簽: 北京網(wǎng)站制作高端網(wǎng)站建設(shè)

我們專(zhuān)注高端建站,小程序開(kāi)發(fā)、軟件系統(tǒng)定制開(kāi)發(fā)、BUG修復(fù)、物聯(lián)網(wǎng)開(kāi)發(fā)、各類(lèi)API接口對(duì)接開(kāi)發(fā)等。十余年開(kāi)發(fā)經(jīng)驗(yàn),每一個(gè)項(xiàng)目承諾做到滿(mǎn)意為止,多一次對(duì)比,一定讓您多一份收獲!

本文章出于推來(lái)客官網(wǎng),轉(zhuǎn)載請(qǐng)表明原文地址:https://www.tlkjt.com/web/13828.html
推薦文章

在線(xiàn)客服

掃碼聯(lián)系客服

3985758

回到頂部