MySQL查詢優(yōu)化(三):深度解讀 MySQL客戶端和服務(wù)端協(xié)議

如果需要從 MySQL 服務(wù)端獲得很高的性能象踊,最佳的方式就是花時間研究 MySQL 優(yōu)化和執(zhí)行查詢的機制锉矢。一旦理解了這些,大部分的查詢優(yōu)化是有據(jù)可循的询吴,從而使得整個查詢優(yōu)化的過程更有邏輯性掠河。下圖展示了 MySQL 執(zhí)行查詢的過程:

  1. 客戶端將 SQL 語句發(fā)送到服務(wù)端。
  2. 服務(wù)端檢查查詢緩存猛计。如果緩存中已有數(shù)據(jù)唠摹,則直接返回緩存結(jié)果;否則有滑,將 SQL 語句傳遞給下一環(huán)節(jié)跃闹。
  3. 服務(wù)端解析、預(yù)處理和優(yōu)化 SQL 語句后,傳遞到查詢優(yōu)化器中形成查詢計劃望艺。
  4. 查詢執(zhí)行引擎通過調(diào)用存儲引擎接口執(zhí)行查詢計劃苛秕。
  5. 服務(wù)端將查詢結(jié)果返回給客戶端。

上述的幾個步驟都有其復雜性找默,接下來幾篇文章將詳細講述各個環(huán)節(jié)艇劫。查詢優(yōu)化過程尤其復雜,并且理解這一環(huán)節(jié)很重要惩激。


mysql完整查詢過程

MySQL 客戶端/服務(wù)端協(xié)議

雖然并不需要了解 MySQL 客戶端/服務(wù)端協(xié)議的內(nèi)部細節(jié)店煞,但需要從高應(yīng)用層面理解其是如何工作的。這個協(xié)議是半雙工的风钻,這意味著 MySQL 服務(wù)端不同同時發(fā)送和接收消息顷蟀,以及不可以將消息拆成多條短消息發(fā)送。這種機制一方面使得 MySQL 的通信簡單快速骡技,另一方面也增加了一些限制鸣个。例如,這意味著無法進行流控布朦,一旦一方發(fā)送了消息囤萤,另一方在響應(yīng)前必須接收整個消息。這就好像來回打乒乓球一樣是趴,同一時間只有一方有球,只有接到了球才能把它打回去唆途。

客戶端通過單個數(shù)據(jù)包將查詢語句發(fā)送給服務(wù)端,因此在存在大的查詢語句時配置 max_allowed_packet 很重要窘哈。一旦客戶端發(fā)送查詢語句后吹榴,它就只能等待返回結(jié)果。

相反滚婉,服務(wù)端的響應(yīng)通常是由多個數(shù)據(jù)包組成的图筹。一旦服務(wù)端響應(yīng)后,客戶端必須獲取整個結(jié)果集让腹≡妒#客戶端沒法簡單地獲取幾行然后告訴服務(wù)端不要再發(fā)送剩余的數(shù)據(jù)。如果客戶端僅僅需要返回數(shù)據(jù)前面的幾行骇窍,只能是等待服務(wù)端全部數(shù)據(jù)返回后再從中丟棄不需要的數(shù)據(jù)瓜晤,或者是粗暴地斷開連接。不管哪種方式都不是好的選擇腹纳,因此合適的 LIMIT子句就顯得十分重要痢掠。

大部分的 MySQL連接庫支持獲取整個結(jié)果集并在內(nèi)存中緩存起來驱犹,或者是獲取需要的數(shù)據(jù)行。默認的行為通常是獲取整個結(jié)果集然后在內(nèi)存緩存足画。知道這一點很重要雄驹,因為 MySQL 服務(wù)端在所有請求的數(shù)據(jù)行沒返回前,不會釋放這次查詢的鎖和資源淹辞。大部分客戶端庫會讓你感覺數(shù)據(jù)是從服務(wù)端獲取的医舆,實際上這些數(shù)據(jù)可能僅僅是從緩存中讀取的。這在大部分時間是沒問題的象缀,但對于耗時很久或占據(jù)很多內(nèi)存的大數(shù)據(jù)量查詢來說就不合適了蔬将。如果指定了不緩存查詢結(jié)果,那么占用的內(nèi)存會更小央星,并且可以更快地處理結(jié)果霞怀。缺點是這種方式會在查詢時引起
服務(wù)端的鎖和資源占用。

以 PHP 為例莉给,以下是PHP常用的查詢代碼:

<?php
$link = mysql_connect('localhost', 'user', 'password');
$result = mysql_query('SELECT * FROM huge_table', $link);
while ($row = mysql_fetch_array($result)) {
  //處理數(shù)據(jù)結(jié)果
}

?>

這個代碼看起來好像是只獲取了需要的數(shù)據(jù)行里烦。然而,這個查詢通過 mysql_query 的調(diào)用后實際上將全部結(jié)果放到了內(nèi)存中禁谦。而 while 循環(huán)實際上是對內(nèi)存中的數(shù)據(jù)進行循環(huán)迭代。相反废封,如果使用 mysql_unbuffered_query 替代 mysql_query 的話州泊,那就不會緩存結(jié)果。

<?php
$link = mysql_connect('localhost', 'user', 'password');
$result = mysql_unbuffered_query('SELECT * FROM huge_table', $link);
while ($row = mysql_fetch_array($result)) {
  //處理數(shù)據(jù)結(jié)果
}

?>

不同的編程語言處理緩存覆蓋的方式不同漂洋。例如遥皂,Perl 的 DBD::mysql 驅(qū)動需要通過 mysql_use_result 屬性指定 C 語音客戶端庫(默認是 mysql_buffer_result),示例如下:

#!/usr/bin/perl

use DBI;
my $dbn = DBI->connect('DBI:mysql:;host=localhost', 'user', 'password');
my $sth = $dbn->prepare('SELECT * FROM huge_table', {mysql_use_result => 1});
$sth->execute();
while (my $row = $sth->fetchrow_array()) {
    #處理數(shù)據(jù)結(jié)果
}

注意到 prepare 指定了使用結(jié)果而不是緩存結(jié)果刽漂。也可以通過在連接的時候指定演训,這會使得每次查詢都不緩存。

my $dbn = DBI->connect('DBI:mysql:;mysql_use_result=1;host=localhost', 'user', 'password');
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贝咙,一起剝皮案震驚了整個濱河市样悟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌庭猩,老刑警劉巖窟她,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異震糖,居然都是意外死亡趴腋,警方通過查閱死者的電腦和手機论咏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進店門厅贪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卦溢,“玉大人,你說我怎么就攤上這事单寂⊥抡蓿” “怎么了?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵尊沸,是天一觀的道長贤惯。 經(jīng)常有香客問我,道長屁商,這世上最難降的妖魔是什么颈墅? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任恤筛,我火速辦了婚禮,結(jié)果婚禮上望伦,老公的妹妹穿的比我還像新娘煎殷。我一直安慰自己,他們只是感情好愕掏,可當我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布顶伞。 她就那樣靜靜地躺著剑梳,像睡著了一般垢乙。 火紅的嫁衣襯著肌膚如雪追逮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天钮孵,我揣著相機與錄音巴席,去河邊找鬼诅需。 笑死,一個胖子當著我的面吹牛堰塌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播料睛,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼施籍!你這毒婦竟也來了概漱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤竿裂,失蹤者是張志新(化名)和其女友劉穎照弥,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悔常,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年矫户,在試婚紗的時候發(fā)現(xiàn)自己被綠了皆辽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡驱闷,死狀恐怖九秀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情痹换,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布娇豫,位于F島的核電站冯痢,受9級特大地震影響框杜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜咪辱,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一历恐、第九天 我趴在偏房一處隱蔽的房頂上張望专筷。 院中可真熱鬧,春花似錦磷蛹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至再层,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蒿秦,已是汗流浹背蛋济。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工渡处, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人医瘫。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓醇份,卻偏偏與公主長得像,于是被迫代替她去往敵國和親僚纷。 傳聞我的和親對象是個殘疾皇子怖竭,可洞房花燭夜當晚...
    茶點故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容