关于mysql的query_cache熟习的误区[MySQL防范]
本文“关于mysql的query_cache熟习的误区[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 :==
<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;
}
这个办法在一开始就会对query举行处理(代码第4行),将开首和末尾的garbage remove掉.
看到这里,我们基本已经明了了,mysql会对输入的query举行预处理,将空格等东西给处理掉,所以不会开首的空格不会影响到query_cache,因为对mysql来说,就是一条query.
以上是“关于mysql的query_cache熟习的误区[MySQL防范]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
本文地址: | 与您的QQ/BBS好友分享! |