PHP查詢MySQL海量數(shù)據(jù)內(nèi)存占用分析
  • 更新時(shí)間:2024-10-28 16:19:40
  • 網(wǎng)站建設(shè)
  • 發(fā)布時(shí)間:1年前
  • 473

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

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

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

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

//.

}

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

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

mysql_查詢()

mysql_unbuffered_query()

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

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

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

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

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

PHP_FUNCTION(mysql_query)

{

php_mysql_do_query(INTERNAL_FUNCTION_PARAM_PASSTHRU,MYSQL_STORE_RESULT);

}

/*}}}*/

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

向MySQL 發(fā)送SQL 查詢,不獲取和緩沖結(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):

如果(使用存儲==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() 來避免直接內(nèi)存占用。如果在遍歷過程中結(jié)果沒有被“PHP緩存”(比如放在一個(gè)數(shù)組中),雖然整個(gè)執(zhí)行過程操作了10萬條或者百萬條或者更多的數(shù)據(jù),但是PHP占用的內(nèi)存總是很小的。

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

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

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

在線客服

掃碼聯(lián)系客服

3985758

回到頂部