《Mysql學(xué)習(xí)對(duì)于mysql的query_cache認(rèn)識(shí)的誤區(qū)》要點(diǎn):
本文介紹了Mysql學(xué)習(xí)對(duì)于mysql的query_cache認(rèn)識(shí)的誤區(qū),希望對(duì)您有用。如果有疑問(wèn),可以聯(lián)系我們。
其實(shí),這一種說(shuō)法是不完全正確的.首先第一點(diǎn),mysql的query_cache的鍵值并不是簡(jiǎn)單的query,而是query加databasename加flag.這個(gè)從源碼中就可以看出.在這里不做重點(diǎn)描述,后續(xù)可以針對(duì)于這一點(diǎn)再具體分析.重要的是第二點(diǎn),是不是加了空格,mysql就認(rèn)為是不同的查詢呢?實(shí)際上這個(gè)是要分情況而言的,要看這個(gè)空格加在哪. 如果空格是加在query之前,比如是在query的起始處加了空格,這樣是絲毫不影響query cache的結(jié)果的,mysql認(rèn)為這是一條query, 而如果空格是在query中,那會(huì)影響query cache的結(jié)果,mysql會(huì)認(rèn)為是不同的query.
下面我們通過(guò)實(shí)驗(yàn)及源碼具體分析.首先,我們先試驗(yàn)一下:MYSQL應(yīng)用
首先,我們看一下mysql query_cache的狀態(tài):MYSQL應(yīng)用
MYSQL應(yīng)用
首先,我們可以確認(rèn),mysql的query_cache功能是打開(kāi)的.MYSQL應(yīng)用
其次,我們看一下?tīng)顟B(tài):MYSQL應(yīng)用
MYSQL應(yīng)用
因?yàn)檫@個(gè)db是新的db,所以hits,inset都為0,現(xiàn)在我們執(zhí)行一條select語(yǔ)句:MYSQL應(yīng)用
狀態(tài)變?yōu)椋?span id="im1cbna6vd" class="showhide">MYSQL應(yīng)用
MYSQL應(yīng)用
可以看到,執(zhí)行一條select后,現(xiàn)在的qcache狀態(tài)為,insert+1,這樣我們就可以推斷出,現(xiàn)在剛才那條select語(yǔ)句已經(jīng)加入了qcache中.那我們現(xiàn)在再將剛才那條sql前面加上空格,看看會(huì)怎樣呢?MYSQL應(yīng)用
MYSQL應(yīng)用
請(qǐng)注意,這條sql,比剛才那條sql前面多了一個(gè)空格.MYSQL應(yīng)用
按照網(wǎng)上的理論,這條sql應(yīng)該會(huì)作為另一個(gè)鍵而插入另一個(gè)cache,不會(huì)復(fù)用先前的cache,但結(jié)果呢?MYSQL應(yīng)用
MYSQL應(yīng)用
我們可以看到,hits變?yōu)榱?,而inserts根本沒(méi)變,這就說(shuō)明了,這條在前面加了空格的query命中了沒(méi)有空格的query的結(jié)果集.從這,我們就可以得出結(jié)論,網(wǎng)上先前流傳的說(shuō)法,是不嚴(yán)謹(jǐn)?shù)?MYSQL應(yīng)用
那究竟是怎么回事呢?到底應(yīng)該如何呢?為什么前面有空格的會(huì)命中了沒(méi)有空格的query的結(jié)果集.其實(shí),這些我們可以通過(guò)源碼獲得答案.MYSQL應(yīng)用
翻看下mysql的源碼,我這翻看的是5.1的,在send_result_to_client(這個(gè)函數(shù)既是mysql調(diào)用query_cache的函數(shù))這個(gè)函數(shù)里面有這樣一段,這段代碼,、
MYSQL應(yīng)用
代碼如下:
/*
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,也就是說(shuō),在語(yǔ)句開(kāi)始之前的多余的空格已經(jīng)被處理過(guò)了,在dispache_command這個(gè)函數(shù)中去掉了.
我們看下dispache_command這個(gè)方法,在這個(gè)方法里有這樣一段:
MYSQL應(yīng)用
代碼如下:
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è)方法在一開(kāi)始就會(huì)對(duì)query進(jìn)行處理(代碼第4行),將開(kāi)頭和末尾的garbage remove掉.
看到這里,我們基本已經(jīng)明了了,mysql會(huì)對(duì)輸入的query進(jìn)行預(yù)處理,將空格等東西給處理掉,所以不會(huì)開(kāi)頭的空格不會(huì)影響到query_cache,因?yàn)閷?duì)mysql來(lái)說(shuō),就是一條query.
轉(zhuǎn)載請(qǐng)注明本頁(yè)網(wǎng)址:
http://www.fzlkiss.com/jiaocheng/3254.html