今天有同学问了一个关于注释的问题,顺藤摸瓜发现一个bug,简要说明下。
有关注释的一些QA
Q: MySQL注释有哪些格式
A:MySQL的注释格式有三种,分别是 /**/ -- 和 #。具体参见手册
Q:在一些导出文件中见过/*! xxx*/,是不是注释?
A: 需要注意的是/*! */ 这种格式,对于MySQL来说不是注释,是能够直接执行的。同时这个格式还支持指定版本号,比如/*!50518 xxxx*/ 表示,若server端版本大于5518,则后续的xxxx作为语句的一部分执行,否则忽略。
Q:语句中的注释会不会发给server
A:默认是不会的。一种方法是在mysql连接中加-c (--comments)参数,则会强制将注释部分也发给Server端。 另一种方法与上一条答案有关,指定一个超过server端的版本号。如果比如指定 /*!121221 xxxx*/,也可以发给server。
Q: 慢查询日志会不会记录注释部分
A: 慢查询会记录语句原文,如果用上面说到的两种方法将注释发给server,若记录到慢查询日志中,就会显示。(也许可以用这种方法来加入语句来源,做业务慢查询分析)
不只是慢查询,如果使用statement格式的binlog,注释部分也会写入到binlog中。
Q: 使用注释的语句能不能使用Query_cache(QC)
A:可以的,QC 会用原文作key,因此若有注释,则注释部分也要求一模一样才会命中QC
Query_cache小背景
QC是一个hash表,key是语句原文,value是查询结果。因此要求一模一样的语句才会命中。
Bug描述
若你的语句中是这么写select * from t /*!121221 just test*/. 按照上面说到的,这个语句是会被全文发到server端,不用怕语法错误,因为121221这个版本号大于现有的所有可用版本。因此实际执行的是select * from t;
如果query_cache正常打开,会看到第一次执行后show status like 'qcache_inserts';值确实+1.
然后再次执行,发现Qcache_hits并没有+1,反而是Qcache_not_cached +1.
说明这个语句虽然被插入QC中,但是却用不上
Bug分析
如果这个查询是慢查询,我们可以在慢查询日志中看到,它记录的是 select * from t /* 121221 just test*/。 ‘!’被换成了空格。
这个替换是在解析阶段发生的。
这样就有问题了:
1、 判断QC是否命中是在解析之前,也就是SQL的原文
2、 第一次执行不命中QC,需要执行,执行期间将!替换成空格
3、 结果在插入QC中,但是此时的key,已经是替换过的。
4、 下一次执行使用的仍然是带!的,因此仍然无法命中
一种解决方法
Percona和MariaDB(5.5+)中有一个特性,刚好绕过这个问题。
参数query_cache_strip_comments用于控制QC中是否去掉SQL语句的注释部分。默认是OFF,若打开,插入QC中的是原语句,可以解决这个问题。
'!'为什么要替换
这个问题的是由解析器将/*! */替换成/* */ 造成的。在5.1其实没有这个替换行为(感谢@飞哥最爱白菜 指出)。为什么MySQL要加上这个动作呢?
原因是我们上面提到的,binlog中会记录语句原文,包括/*!VERSION xxx*/的内容。
这样在主从同步时,若VERSION大于主库版本而小于从库版本(官方是承诺向下兼容的),则可能会出现主从执行不一致的问题。
主库发现xxx不会被执行,就做了替换,语句变成 /* VERSION xxx*/,这是个标准的注释,从库也不会执行xxx部分。
因此属于解决bug的时候引入的。
分享到:
相关推荐
mycat连接数据库8.0以上用1.6.4有bug,经常无法插入;使用1.6.5以上版本 程序连接报错query_cache_size。 本资源基于1.6.7基础之上进行优化
基于源码修改JDBC8驱动连接Mycat1.6报错 Unknown system variable 'query_cache_size' ,配置好mycat相应配置直接bin目录启动即可
THREAD_CACHE MySQL里面为了提高客户端请求创建连接过程的性能,提供了一个连接池也就是 Thread_Cache池,将空闲的连接线程放在连接池中,而不是立即销毁.这样的好处就是,当又有一个新的请求的时候,mysql不会立即去创建...
会发现其变量have_query_cache的值是yes,MYSQL初学者很容易以为这个参数为YES就代表开启了查询缓存,实际上是不对的,该参数表示当前版本的MYSQL是否支持Query Cache,实际上是否开启查询缓存是看另外一个参数的值:...
如果空格是加在query之前,比如是在query的起始处加了空格,这样是丝毫不影响query cache的结果的,mysql认为这是一条query, 而如果空格是在query中,那会影响query cache的结果,mysql会认为是不同的query
当Mysql访问一个表时,如果在Mysql表缓冲区中还有空间,那么这个表就被打开并放入表缓冲区,这样做的好处是可以更快速地访问表中的内容。一般来说,可以通过查看数据库运行峰值时间的状态值Open_tables和Opened_...
以前自己写的一套mysql分库分表的查询代码,查询速度大概在1300-Mysql_Query_By_Aspect
在mysql数据库连接时碰到Warning: mysql_fetch_array() expects …错误提示,根据我的经验这个是sql返回的query为空了,我们没有加己判断直接使用了. mysql_fetch_array()函数导致的,下面我们一起来看问题解决方案,我...
navicat112_mysql_cs_x64.tar.gz
由于每个客户端连接都会至少访问一个表,因此此参数的值与max_connections有关。 例如,对于 1000 个并行运行的连接,应该让表的缓存至少有 1000 × N ,这里 N 是应用可以执行的查询的一个联接中表的最大数量。此外...
$result = mysql_query($sql); while($row = mysql_fetch_row($result)) { echo $row[‘cid’].’::’.$row[1].' ’; } $result = mysql_query($sql); while($row = mysql_fetch_array($result)) {
Mysql2QueryFilter 过滤框架。 安装 将此行添加到应用程序的 Gemfile 中: gem 'mysql2_query_filter' 然后执行: $ bundle 或者自己安装: $ gem install mysql2_query_filter 用法 require 'mysql2_query...
mysql_affected_rows — 取得前一次 MySQL 操作...mysql_escape_string — 转义一个字符串用于 mysql_query mysql_fetch_array — 从结果集中取得一行作为关联数组 mysql_fetch_assoc — 从结果集中取得一行作为关联数
A simple tool, which can help you bring all data stored in Excel Data Files into MySQLDB, and then you can handle your data in MySQLDB via this tool through Excel. Just try it!
由于每个客户端连接都会至少访问一个表,因此此参数的值与max_connections有关。 缓存机制 当某一连接访问一个表时,MySQL会检查当前已缓存表的数量。如果该表已经在缓存中打开,则会直接访问缓存中的表已加快查询...
主要介绍了MySQL性能优化配置参数之thread_cache和table_cache详解,THREAD_CACHE是Mysql的连接池,table_cache指定表高速缓存的大小,需要的朋友可以参考下
在MySQL中,慢查询的界定时间是由MySQL内置参数变量long_query_time来指定的,其默认值为10(单位:秒),我们可以通过show variables like ‘long_query_time’;指令来查看该参数变量的信息: long_query_time的...