對(duì)于mysql的query_cache認(rèn)識(shí)的誤區(qū)
下面我們通過實(shí)驗(yàn)及源碼具體分析。首先,我們先試驗(yàn)一下:
首先,我們看一下mysql query_cache的狀態(tài):
首先,我們可以確認(rèn),mysql的query_cache功能是打開的。
其次,我們看一下狀態(tài):
因?yàn)檫@個(gè)db是新的db,所以hits,inset都為0,現(xiàn)在我們執(zhí)行一條select語(yǔ)句:
狀態(tài)變?yōu)椋?/P>
可以看到,執(zhí)行一條select后,現(xiàn)在的qcache狀態(tài)為,insert+1,這樣我們就可以推斷出,現(xiàn)在剛才那條select語(yǔ)句已經(jīng)加入了qcache中。那我們現(xiàn)在再將剛才那條sql前面加上空格,看看會(huì)怎樣呢?
請(qǐng)注意,這條sql,比剛才那條sql前面多了一個(gè)空格。
按照網(wǎng)上的理論,這條sql應(yīng)該會(huì)作為另一個(gè)鍵而插入另一個(gè)cache,不會(huì)復(fù)用先前的cache,但結(jié)果呢?
我們可以看到,hits變?yōu)榱?,而inserts根本沒變,這就說明了,這條在前面加了空格的query命中了沒有空格的query的結(jié)果集。從這,我們就可以得出結(jié)論,網(wǎng)上先前流傳的說法,是不嚴(yán)謹(jǐn)?shù)摹?/P>
那究竟是怎么回事呢?到底應(yīng)該如何呢?為什么前面有空格的會(huì)命中了沒有空格的query的結(jié)果集。其實(shí),這些我們可以通過源碼獲得答案。
翻看下mysql的源碼,我這翻看的是5.1的,在send_result_to_client(這個(gè)函數(shù)既是mysql調(diào)用query_cache的函數(shù))這個(gè)函數(shù)里面有這樣一段,這段代碼,、
/*
Test if the query is a SELECT
(pre-space is removed in dispatch_command).
First '/' looks like comment before command it is not
frequently appeared in real life, consequently we can
check all such queries, too.
*/
if ((my_toupper(system_charset_info, sql[i]) != 'S' ||
my_toupper(system_charset_info, sql[i + 1]) != 'E' ||
my_toupper(system_charset_info, sql[i + 2]) != 'L') &&
sql[i] != '/')
{
DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
goto err;
}
是在檢驗(yàn)語(yǔ)句是否為select語(yǔ)句,重點(diǎn)是上面那段注釋。特別是括弧中的,pre-space is removed in dispatch_command,也就是說,在語(yǔ)句開始之前的多余的空格已經(jīng)被處理過了,在dispache_command這個(gè)函數(shù)中去掉了。
我們看下dispache_command這個(gè)方法,在這個(gè)方法里有這樣一段:
if (alloc_query(thd, packet, packet_length))
break; // fatal error is set
char *packet_end= thd->query() + thd->query_length();
/* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */
const char* end_of_stmt= NULL;
在這里,會(huì)調(diào)用alloc_query方法,我們看下這個(gè)方法的內(nèi)容:
bool alloc_query(THD *thd, const char *packet, uint packet_length)
{
char *query;
/* Remove garbage at start and end of query */
while (packet_length > 0 && my_isspace(thd->charset(), packet[0]))
{
packet++;
packet_length--;
}
const char *pos= packet + packet_length; // Point at end null
while (packet_length > 0 &&
(pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
{
pos--;
packet_length--;
}
/* We must allocate some extra memory for query cache
The query buffer layout is:
buffer :==
<statement> The input statement(s)
'\0' Terminating null char (1 byte)
<length> Length of following current database name (size_t)
<db_name> Name of current database
<flags> Flags struct
*/
if (! (query= (char*) thd->memdup_w_gap(packet,
packet_length,
1 + sizeof(size_t) + thd->db_length +
QUERY_CACHE_FLAGS_SIZE)))
return TRUE;
query[packet_length]= '\0';
/*
Space to hold the name of the current database is allocated. We
also store this length, in case current database is changed during
execution. We might need to reallocate the 'query' buffer
*/
char *len_pos = (query + packet_length + 1);
memcpy(len_pos, (char *) &thd->db_length, sizeof(size_t));
thd->set_query(query, packet_length);
/* Reclaim some memory */
thd->packet.shrink(thd->variables.net_buffer_length);
thd->convert_buffer.shrink(thd->variables.net_buffer_length);
return FALSE;
}
這個(gè)方法在一開始就會(huì)對(duì)query進(jìn)行處理(代碼第4行),將開頭和末尾的garbage remove掉。
看到這里,我們基本已經(jīng)明了了,mysql會(huì)對(duì)輸入的query進(jìn)行預(yù)處理,將空格等東西給處理掉,所以不會(huì)開頭的空格不會(huì)影響到query_cache,因?yàn)閷?duì)mysql來(lái)說,就是一條query。
相關(guān)文章
MySQL數(shù)據(jù)庫(kù)運(yùn)維之?dāng)?shù)據(jù)恢復(fù)的方法
本篇文章主要介紹了MySQL數(shù)據(jù)庫(kù)運(yùn)維之?dāng)?shù)據(jù)恢復(fù)的方法,此處總結(jié)一下恢復(fù)方案,并結(jié)合數(shù)據(jù)庫(kù)的二進(jìn)制日志做下數(shù)據(jù)恢復(fù)的示范。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2018-06-06MySQL中的驅(qū)動(dòng)表與被驅(qū)動(dòng)表及含義
使用join連接查詢時(shí)如果有where條件,則MySQL執(zhí)行器會(huì)根據(jù)查詢條件過濾后的結(jié)果自動(dòng)選擇驅(qū)動(dòng)表或被驅(qū)動(dòng)表,這篇文章主要介紹了MySQL的驅(qū)動(dòng)表與被驅(qū)動(dòng)表,需要的朋友可以參考下2023-10-10MySQL中insert語(yǔ)句的使用與優(yōu)化教程
這篇文章主要介紹了MySQL中insert語(yǔ)句的使用與優(yōu)化教程,使用insert語(yǔ)句插入數(shù)據(jù)是MySQL入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2016-03-03C#列出局域網(wǎng)中可用SQL Server服務(wù)器
SQLDMO(SQL Distributed Management Objects,SQL分布式管理對(duì)象)封裝了Microsoft SQL Server數(shù)據(jù)庫(kù)中的對(duì)象。SQLDMO是Microsoft SQL Server中企業(yè)管理器所使用的應(yīng)用程序接口,所以它可以執(zhí)行很多功能,其中當(dāng)然也包括對(duì)數(shù)據(jù)庫(kù)的備份和恢復(fù)。2008-04-04windows下MySQL 5.7.3.0安裝配置圖解教程(安裝版)
這篇文章主要介紹了windows下MySQL 5.7.3.0安裝配置圖解教程(安裝版),需要的朋友可以參考下2016-04-04美團(tuán)網(wǎng)技術(shù)團(tuán)隊(duì)分享的MySQL索引及慢查詢優(yōu)化教程
這篇文章主要介紹了美團(tuán)網(wǎng)技術(shù)團(tuán)隊(duì)分享的MySQL索引及慢查詢優(yōu)化教程,結(jié)合了實(shí)際的磁盤IO情況對(duì)一些優(yōu)化方案作出了分析,十分推薦!需要的朋友可以參考下2015-11-11