對于mysql的query_cache認識的誤區

一直以來,對于mysql的query_cache,在網上就流行著這樣的說法,對于mysql的query_cache鍵值就是mysql的query,所以,如果在query中有任何的不同,包括多了個空格,都會導致mysql認為是不同的查詢

其實,這一種說法是不完全正確的。首先第一點,mysql的query_cache的鍵值并不是簡單的query,而是query加databasename加flag。這個從源碼中就可以看出。在這里不做重點描述,后續可以針對于這一點再具體分析。重要的是第二點,是不是加了空格,mysql就認為是不同的查詢呢?實際上這個是要分情況而言的,要看這個空格加在哪。 如果空格是加在query之前,比如是在query的起始處加了空格,這樣是絲毫不影響query cache的結果的,mysql認為這是一條query, 而如果空格是在query中,那會影響query cache的結果,mysql會認為是不同的query。

下面我們通過實驗及源碼具體分析。首先,我們先試驗一下:

首先,我們看一下mysql query_cache的狀態:

首先,我們可以確認,mysql的query_cache功能是打開的。

其次,我們看一下狀態:

因為這個db是新的db,所以hits,inset都為0,現在我們執行一條select語句:

狀態變為:

可以看到,執行一條select后,現在的qcache狀態為,insert+1,這樣我們就可以推斷出,現在剛才那條select語句已經加入了qcache中。那我們現在再將剛才那條sql前面加上空格,看看會怎樣呢?

請注意,這條sql,比剛才那條sql前面多了一個空格。

按照網上的理論,這條sql應該會作為另一個鍵而插入另一個cache,不會復用先前的cache,但結果呢?

我們可以看到,hits變為了1,而inserts根本沒變,這就說明了,這條在前面加了空格的query命中了沒有空格的query的結果集。從這,我們就可以得出結論,網上先前流傳的說法,是不嚴謹的。

那究竟是怎么回事呢?到底應該如何呢?為什么前面有空格的會命中了沒有空格的query的結果集。其實,這些我們可以通過源碼獲得答案。

翻看下mysql的源碼,我這翻看的是5.1的,在send_result_to_client(這個函數既是mysql調用query_cache的函數)這個函數里面有這樣一段,這段代碼,、
代碼如下:
/*
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;
}

是在檢驗語句是否為select語句,重點是上面那段注釋。特別是括弧中的,pre-space is removed in dispatch_command,也就是說,在語句開始之前的多余的空格已經被處理過了,在dispache_command這個函數中去掉了。

我們看下dispache_command這個方法,在這個方法里有這樣一段:
代碼如下:
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;

在這里,會調用alloc_query方法,我們看下這個方法的內容:
代碼如下:
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 :==
The input statement(s)

久久精品国产亚洲AV香蕉| 99久久国产热无码精品免费久久久久| 91精品国产高清91久久久久久| 日韩精品久久久肉伦网站| 狠狠88综合久久久久综合网 | 久久这里的只有是精品23| 人妻精品久久无码专区精东影业| 国产精品女同久久久久电影院| 精品综合久久久久久97超人| 亚洲国产成人久久综合野外| 色综合久久综合中文综合网| 久久婷婷色综合一区二区| 久久久久亚洲AV无码专区体验| 久久久九九有精品国产| 伊人久久久AV老熟妇色| 亚洲美日韩Av中文字幕无码久久久妻妇| 久久噜噜久久久精品66| 精品久久久久久久久中文字幕| 日日狠狠久久偷偷色综合免费| 国产成人综合久久精品尤物| 精品久久久久久久久午夜福利| 久久乐国产精品亚洲综合| 国产精品久久一区二区三区| 久久久久久综合网天天| 97精品依人久久久大香线蕉97| 99久久综合狠狠综合久久| 九九精品99久久久香蕉| 色偷偷偷久久伊人大杳蕉| 午夜精品久久久久久| 精品无码久久久久久久久久| 久久国产福利免费| 久久国产精品99久久久久久老狼| 亚洲va久久久噜噜噜久久狠狠| 亚州日韩精品专区久久久| 久久嫩草影院免费看夜色| 久久久久亚洲AV综合波多野结衣| 超级碰久久免费公开视频| 久久久综合九色合综国产| 天天综合久久久网| 国内精品久久久久久久亚洲| 久久91精品综合国产首页|