PHP到MySQL數(shù)據(jù)查詢(xún)過(guò)程概述
HP層到MySQL層
Php到sql組件層次如下圖所示:
ext/mysqli和ext/mysql 是客戶(hù)端的擴(kuò)展程序庫(kù)(庫(kù)函數(shù)) ,在客戶(hù)端腳本層面的擴(kuò)展庫(kù)。 Mysqli庫(kù)是mysql庫(kù)的擴(kuò)展版本,擴(kuò)展版本增加了列版定(Bind Column)綁定。PDO (PHP Data Object) 是另外一種面向數(shù)據(jù)對(duì)象的 擴(kuò)展庫(kù)。這些擴(kuò)展庫(kù)直接面向編程者,而它的底層實(shí)現(xiàn)是mysql連接引擎(如mysqlnd和libmysql )(參考 http://bbs.chinaunix.net/thread-3679393-1-1.html 、http://blog.csdn.net/treesky/article/details/7286098 )。
mysqlnd和libmysql 是PHP端(客戶(hù)端)的數(shù)據(jù)庫(kù)連接驅(qū)動(dòng)引擎。libmysql 是通用的數(shù)據(jù)庫(kù)連接引擎,而mysqlnd是專(zhuān)屬PHP開(kāi)發(fā)的連接引擎,從屬于Zend中。 當(dāng)PHP通過(guò)調(diào)用擴(kuò)展庫(kù)(ext/mysqli和ext/mysql)中的mysql_query() 函數(shù)進(jìn)行數(shù)據(jù)庫(kù)查詢(xún)的時(shí)候,Zend引擎將通過(guò)mysql(mysqlnd和libmysql)查詢(xún)引擎向MySQL服務(wù)器發(fā)出查詢(xún)請(qǐng)求。
MySQL層的數(shù)據(jù)查詢(xún)
MySQL服務(wù)器接受到客戶(hù)端的查詢(xún)請(qǐng)求后,查詢(xún)執(zhí)行過(guò)程如上圖所示:
1. 查詢(xún)緩存,如果命中則直接將結(jié)果集返回給到客戶(hù)端,否則進(jìn)入步驟2
2. 對(duì)SQL語(yǔ)句依次進(jìn)行解析、預(yù)處理、查詢(xún)優(yōu)化等操作,最終生成查詢(xún)執(zhí)行計(jì)劃(select的查詢(xún)執(zhí)行計(jì)劃可以通過(guò)explain select 查看)
3. MySQL服務(wù)端的查詢(xún)執(zhí)行引擎將依據(jù)查詢(xún)執(zhí)行計(jì)劃 調(diào)用存儲(chǔ)引擎對(duì)數(shù)據(jù)進(jìn)行查詢(xún)。當(dāng)SQL語(yǔ)句的最后一層關(guān)聯(lián)被執(zhí)行后,將產(chǎn)生查詢(xún)結(jié)果集
4. 查詢(xún)結(jié)果集發(fā)送到客戶(hù)端,傳回的方式有兩種:MySQL服務(wù)端緩存結(jié)果集 或 不緩存,這個(gè)由參數(shù)SQL_BUFFER_RESULT設(shè)置。 并且,如果用戶(hù)設(shè)置了SQL_CACHE 那么本次的查詢(xún)的結(jié)果集的一份副本存儲(chǔ)于 查詢(xún)緩存 中(步驟1相關(guān))。
SQL_CACHE參數(shù)的啟示:
將復(fù)雜的(多個(gè)關(guān)聯(lián))查詢(xún)分解為多條簡(jiǎn)單的查詢(xún),因?yàn)?
1)簡(jiǎn)單查詢(xún)的緩存命中搞、
2)復(fù)雜查詢(xún)結(jié)果的緩存易失效(關(guān)聯(lián)太多表)
3)簡(jiǎn)單查詢(xún)鎖的持有率低
MySQL Server 到 PHP層
通信模式MySQL Server和客戶(hù)端的通信采用“半雙工通信”,意思是:客戶(hù)端和服務(wù)端只能有一個(gè)在讀,并且另外一個(gè)必須是寫(xiě)。
優(yōu)點(diǎn):協(xié)議簡(jiǎn)單,客戶(hù)端和服務(wù)端的寫(xiě)權(quán)限是互斥的
缺點(diǎn):無(wú)法進(jìn)行流量控制,一端開(kāi)始發(fā)送消息,另一端要完整的接受這個(gè)消息后才能響應(yīng)它。
啟示:服務(wù)端查詢(xún)后的結(jié)果集發(fā)送給客戶(hù)端,客戶(hù)端(客戶(hù)端的查詢(xún)引擎,例如mysqlnd)必須完整的接受。所以,如果只需要少數(shù)行,記得在sql語(yǔ)句添加使用limit,少用select *。
結(jié)果集回傳模式結(jié)果集回傳中,每一行記錄都通過(guò) 客戶(hù)端-服務(wù)器通信協(xié)議進(jìn)行包裝,然后再交接給下層的tcp協(xié)議;當(dāng)然,在tcp層,可以先緩存每行記錄的協(xié)議包,組成大包在發(fā)出(對(duì)應(yīng)用層透明)。
MySQL服務(wù)端只有將結(jié)果集全部發(fā)送給客戶(hù)端后,才能釋放結(jié)果集所占用的buffer。
服務(wù)端緩存模式
客戶(hù)端命令: mysql_unbuffer_query(),在客戶(hù)端的sql驅(qū)動(dòng)擴(kuò)展(mysqlnd)中不設(shè)置結(jié)果集的緩存,所以在fecth_array_xxx從結(jié)果集中讀取一條記錄時(shí),需要從服務(wù)端的緩沖區(qū)中讀取。
服務(wù)端無(wú)緩存模式
客戶(hù)端命令: mysql_query(),在客戶(hù)端的sql驅(qū)動(dòng)擴(kuò)展(mysqlnd)中設(shè)置了buffer用于緩存服務(wù)端的結(jié)果集,所以在fecth_array_xxx從結(jié)果集中讀取一條記錄時(shí),是直接從mysqlnd擴(kuò)展的緩沖區(qū)中取得row。
小結(jié)
如果結(jié)果集很大: 服務(wù)端無(wú)緩存模式可以減少服務(wù)端的內(nèi)存壓力喲,但是占用客戶(hù)端的內(nèi)存。這樣只有看情況取舍了。
PHP層到用戶(hù)層
在客戶(hù)端,于服務(wù)端對(duì)接的是mysql擴(kuò)展引擎(libmysql 或者 mysqlnd),而用戶(hù)層是通過(guò)擴(kuò)展庫(kù)(ext/mysql 或 ext/mysqli)和mysql引擎進(jìn)行交互(啟示就是調(diào)用引擎的api讀取結(jié)果集)。
引 擎libmysql 和 mysqlnd 的機(jī)制并不同,主要區(qū)別是mysqlnd是轉(zhuǎn)為php寫(xiě)的,被編譯到zend內(nèi)部。而libmysql是通用的庫(kù),zend需要調(diào)用該庫(kù)實(shí)現(xiàn)數(shù)據(jù)庫(kù)的連 接。在這種卻別下,mysqlnd和zend具有更好的粘合性,在數(shù)據(jù)傳輸?shù)接脩?hù)層時(shí),少了一層數(shù)據(jù)的拷貝。具體的架構(gòu)區(qū)別如下圖所示。圖中,五角星表示 緩存 buffer。
ext/mysqli和ext/mysql 是客戶(hù)端的擴(kuò)展程序庫(kù)(庫(kù)函數(shù)) : 在客戶(hù)端腳本層面mysqlInd和libmysql 是MySQL Server端的驅(qū)動(dòng)程序。其中,libmysql是通用的MySQL查詢(xún)驅(qū)動(dòng)程序,而mysqlnd是專(zhuān)為PHP設(shè)置的基于Zend引擎的SQL驅(qū)動(dòng),即mysqlnd的數(shù)據(jù)驅(qū)動(dòng)動(dòng)作需要經(jīng)過(guò)Zend和mysqlserver交互,而libmysql直接和mysqlserver交互的。
對(duì)比:
ext/mysqli(或者ext/mysql)和libmysql的數(shù)據(jù)庫(kù)查詢(xún)中的過(guò)程為:
1)mysqi向libmysql驅(qū)動(dòng)發(fā)送查詢(xún)請(qǐng)求
2)Libmysql執(zhí)行請(qǐng)求并得到結(jié)果集存儲(chǔ)域libmysql的buffers中
3)Mysqli申請(qǐng)內(nèi)存:zval指定的一塊buffer
4)Mysqii從libmysql拷貝結(jié)果集到zval指定的buffer中
ext/mysqli(或者ext/mysql)和mysqlnd的數(shù)據(jù)庫(kù)查詢(xún)中的過(guò)程為:
1) mysqi向mysqlnd驅(qū)動(dòng)發(fā)送查詢(xún)請(qǐng)求
2) mysqlnd驅(qū)動(dòng)通過(guò)zend引擎執(zhí)行sql查詢(xún),結(jié)果集的每一行由一個(gè)buffer存儲(chǔ)(各個(gè)buffer是分散的)
3) Mysqlnd創(chuàng)建多個(gè)zval,并指向這些buffers
例如:
在ext/mysql & libmysql 中,libmysql驅(qū)動(dòng)執(zhí)行SQL語(yǔ)句后得到結(jié)果集Row1~Row3,然后ext/mysql將結(jié)果集拷貝到zend buffer中,之后mysqli_fetch_xxx函數(shù)從該區(qū)域內(nèi)存中讀取結(jié)果集中的內(nèi)容。
在ext/mysqli & mysqlInd 中,mysqlnd 驅(qū)動(dòng)執(zhí)行SQL語(yǔ)句得到結(jié)果集Row1~Row3,其中,每個(gè)row直接由zend的一個(gè)buffer存儲(chǔ),并由一個(gè)zval指向??蛻?hù)端通過(guò)映射直接從 該內(nèi)存區(qū)域中讀取結(jié)果實(shí)現(xiàn)mysqli_fetch_xxx。
小結(jié)
mysqlnd和zend更具有粘合性,在sql查詢(xún)驅(qū)動(dòng)中,mysqlnd通過(guò)zend引擎訪(fǎng)問(wèn)數(shù)據(jù)庫(kù),并直接將將結(jié)果存儲(chǔ)域zend的buffer中,相比libmysql驅(qū)動(dòng)(獨(dú)立于zend),少了一次結(jié)果集緩存拷貝。
參考
《高性能MySQL》
http://www.cnxct.com/libmysql-mysqlnd-which-is-best-and-what-about-mysqli-pdomysql-mysql/
http://www.cnxct.com/wp-content/uploads/2012/12/andrey-mysqlnd.pdf
版權(quán)聲明:本文為博主(http://blog.csdn.net/ordeder)原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。
以上就介紹了PHP到MySQL數(shù)據(jù)查詢(xún)過(guò)程概述,包括了方面的內(nèi)容,希望對(duì)MySql有興趣的朋友有所幫助。
電腦/手機(jī)小常識(shí):取消共享文檔
默認(rèn)情況下,在Windows XP中打開(kāi)我的電腦,會(huì)看到在硬盤(pán)圖標(biāo)上方有一些文件夾。這些就是“共享文件夾”,這里有每一個(gè)用來(lái)戶(hù)共享文件所用的文件夾。我們可以讓這些文件夾在我的 電腦中消失,原理很簡(jiǎn)單,只要打開(kāi)注冊(cè)表找到如下位置:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows \CurrentVersion\ Explorer\MyComputer\NameSpace\DelegateFolders,把 {59031a47-3f72-44a7-89c5-5595fe6b30ee}鍵值刪掉,下次打開(kāi)我的電腦,這些煩人的文件夾就不復(fù)存在了。