对于mysql的query_cache认识的误区

标签: MySQL优化设计 query_cache | 发表时间:2012-02-29 12:37 | 作者:OurMySQL
出处:http://ourmysql.com

一直以来,对于mysql的query_ ,在网上就流行着这样的说法,“对于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的状态:

image

首先,我们可以确认,mysql的query_cache功能是打开的。

其次,我们看一下状态:

image

因为这个db是新的db,所以hits,inset都为0,现在我们执行一条select语句:

 

状态变为:

image

可以看到,执行一条select后,现在的qcache状态为, +1,这样我们就可以推断出,现在刚才那条select语句已经加入了qcache中。那我们现在再将刚才那条sql前面加上空格,看看会怎样呢?

image

请注意,这条sql,比刚才那条sql前面多了一个空格。

按照网上的理论,这条sql应该会作为另一个键而插入另一个cache,不会复用先前的cache,但结果呢?

image

我们可以看到,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_  ).

      First '/' looks like comment before    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 +
                                             _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 Query Cache 小结

- Eneri - Sky.Jian 朝阳的天空
最近经常有人问我 MySQL Query Cache 相关的问题,就整理一点 MySQL Query Cache 的内容,以供参考. 顾名思义,MySQL Query Cache 就是用来缓存和 Query 相关的数据的. 具体来说,Query Cache 缓存了我们客户端提交给 MySQL 的 SELECT 语句以及该语句的结果集.

巧用query cache

- - OurMySQL
   收到一用户反馈其应用日志中狂报错误,获取连接超时:. 同时应用报错超出了数据库的最大连接数:max connections:. 这种情况很有可能是有慢sql占用了连接池中的连接没有释放,导致后续进来的请求迟迟获取不到连接池中的连接,导致请求报错,登录数据库排查发现如下sql出现执行非常的慢:.

[MySQL FAQ]系列 — 为什么要关闭query cache,如何关闭

- - MySQL中文网
备注:插图来自淘宝苏普的博客并保留水印,如果觉得不当还请及时告知 :). 写在前面:MySQL的query cache大部分情况下其实只是鸡肋而已,建议全面禁用. 当然了,或许在你的场景下还是挺好的,还能发挥作用,那就继续使用吧,把本文当做参考就好. 不过,可能有的人人为只需要把 query_cache_size 大小调整为 0 就可以了,可以忽略 query_cache_type 参数的值,反正它也是可以在线调整的.

[MySQL FAQ]系列 — 线上环境到底要不要开启query cache

- - MySQL中文网
Query Cache(查询缓存,以下简称QC)存储SELECT语句及其产生的数据结果,特别适用于:频繁提交同一个语句,并且该表数据变化不是很频繁的场景,例如一些静态页面,或者页面中的某块不经常发生变化的信息. InnoDB Buffer Pool或者. MyISAM key buffer里读取结果.

[转]用mysqldumpslow分析mysql的slow query log

- - 小彰
mysql有一个功能就是可以log下来运行的比较慢的sql语句,默认是没有这个log的,为了开启这个功能,要修改my.cnf或者在mysql启动的时候加入一些参数. 如果在my.cnf里面修改,需增加如下几行. long_query_time 是指执行超过多久的sql会被log下来,这里是1秒. log-slow-queries 设置把日志写在那里,可以为空,系统会给一个缺省的文件 host_name-slow.log,我生成的log就在mysql的data目录.

MySQL SQL Tuning:Profile定位单条QUERY性能瓶颈

- - CSDN博客数据库推荐文章
当生了病的query来就诊时,如果身为医生的我们"胡庸医乱用虎狼药". 不仅于事无补,还浪费了大量的人力和时间成本,甚至会拖垮服务器. 所以,我们在接受优化一条SQL,第一件事情便是要明白query病在哪里. 是CPU?只有明白瓶颈在哪里,方可对症下药,也才能药到病除. 而MySQL QUERY Profiler是一个使用非常方便的QUERY诊断工具,5.0引入.

高性能MySql进化论(四):Summary,Cache,Counter表的使用

- - CSDN博客数据库推荐文章
在实际的应用中,往往会定期的对一个周期内的系统数据进行统计分析. 例如某购物网站定期的统计商品在一个月/年期内的销售情况,如果采用扫描所有相关表的方式在某个时间点进行统计分析, 由于数据量很大,以及表结构的复杂,性能可能会是很大的问题. 针对这种情况可以通过使用Summary,Cache,Counter 数据表的方式来提高分析的效率.

Guava cache

- - 孟飞阳的博客
Guava Cache是一个全内存的本地缓存实现,它提供了线程安全的实现机制. 整体上来说Guava cache 是本地缓存的不二之选,简单易用,性能好.    Guava Cache有两种创建方式:.   通过这两种方法创建的cache,和通常用map来缓存的做法比,不同在于,这两种方法都实现了一种逻辑——从缓存中取key X的值,如果该值已经缓存过了,则返回缓存中的值,如果没有缓存过,可以通过某个方法来获取这个值.

Java Cache系列之Guava Cache

- - BlogJava-首页技术区
然而作为工具库中的一部分,我们自然不能期待Guava对Cache有比较完善的实现. 因而Guava中的Cache只能用于一些把Cache作为一种辅助设计的项目或者在项目的前期为了实现简单而引入. 在Guava CacheBuilder的注释中给定Guava Cache以下的需求:. 对于这样的需求,如果要我们自己来实现,我们应该怎么设计.