时间:2021-05-23
其实,这一种说法是不完全正确的。首先第一点,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的函数)这个函数里面有这样一段,这段代码,、
复制代码 代码如下:
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();
const char* end_of_stmt= NULL;
在这里,会调用alloc_query方法,我们看下这个方法的内容:
复制代码 代码如下:
bool alloc_query(THD *thd, const char *packet, uint packet_length)
{
char *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--;
}
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';
char *len_pos = (query + packet_length + 1);
memcpy(len_pos, (char *) &thd->db_length, sizeof(size_t));
thd->set_query(query, packet_length);
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。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
可将如下语句query_cache_size=268435456query_cache_type=1query_cache_limit=1048576存放到/e
php提示错误:Warning:mysql_query()[function.mysql-query]:Accessdeniedforuser'ODBC'@'l
Errormessages:•[Type]查询语句安全威胁•[Query]SELECT*FROMcom
1.从数据库中查询出来的数据,放在数组中复制代码代码如下:$query=mysql_query($SQL);while($row=mysql_fetch_arr
mysql_query("BEGIN");//开始一个事务mysql_query("SETAUTOCOMMIT=0");//设置事务不自动commit$inse