发现一个timestampdiff无法正确判断列值的BUG,看下面例子:

--测试表如下:
mysql> select * from test;
+----+---------------------+
| id | col2                |
+----+---------------------+
|  1 | 2019-03-20 00:00:00 |
|  2 | 2019-04-01 00:00:00 |
|  3 | 2019-04-20 00:00:00 |
|  4 | 2019-04-01 14:30:00 |
+----+---------------------+
4 rows in set (0.00 sec)mysql> desc test;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type      | Null | Key | Default           | Extra                       |
+-------+-----------+------+-----+-------------------+-----------------------------+
| id    | int(11)   | NO   |     | NULL              |                             |
| col2  | timestamp | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
2 rows in set (0.00 sec)--查询2019-04-01 00:00:00以来的数据,不包括2019-04-01 00:00:00:
mysql> select * from test where timestampdiff(second,'2019-04-01 00:00:00',col2)>0;
+----+---------------------+
| id | col2                |
+----+---------------------+
|  3 | 2019-04-20 00:00:00 |
|  4 | 2019-04-01 14:30:00 |
+----+---------------------+
2 rows in set (0.00 sec)--查询距离2019-04-01 00:00:00一个月内的数据:
mysql> select * from test where timestampdiff(month,'2019-04-01 00:00:00',col2)=0;
+----+---------------------+
| id | col2                |
+----+---------------------+
|  1 | 2019-03-20 00:00:00 |
|  2 | 2019-04-01 00:00:00 |
|  3 | 2019-04-20 00:00:00 |
|  4 | 2019-04-01 14:30:00 |
+----+---------------------+
4 rows in set (0.00 sec)--可以看到上面两个查询,有两条重复的数据,分别是id=3和id=4两行
--但是将两个谓词条件却查不到记录:
mysql> select * from test where timestampdiff(second,'2019-04-01 00:00:00',col2)>0 and timestampdiff(month,'2019-04-01 00:00:00',col2)=0;
Empty set (0.00 sec)--进一步查看执行计划以及优化器内部转化:
mysql> desc select * from test where timestampdiff(second,'2019-04-01 00:00:00',col2)>0 and timestampdiff(month,'2019-04-01 00:00:00',col2)=0;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra            |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
|  1 | SIMPLE      | NULL  | NULL       | NULL | NULL          | NULL | NULL    | NULL | NULL |     NULL | Impossible WHERE |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
1 row in set, 1 warning (0.00 sec)mysql> show warnings;
+-------+------+---------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                 |
+-------+------+---------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `sam`.`test`.`id` AS `id`,`sam`.`test`.`col2` AS `col2` from `sam`.`test` where 0 |
+-------+------+---------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
--可以看到优化器显示Impossible WHERE,认为谓词条件是始终不成立的,在warning中我们看到谓词条件转化成了where 0,但是我们分开查询是有结果并且有交集的,不应该是这样的结果。--如果我们将谓词改成timestampdiff(second,'2019-04-01 00:00:00',col2)>=0,就可以查到数据了:
mysql> select * from test where timestampdiff(second,'2019-04-01 00:00:00',col2)>=0 and timestampdiff(month,'2019-04-01 00:00:00',col2)=0;
+----+---------------------+
| id | col2                |
+----+---------------------+
|  1 | 2019-03-20 00:00:00 |
|  2 | 2019-04-01 00:00:00 |
|  3 | 2019-04-20 00:00:00 |
|  4 | 2019-04-01 14:30:00 |
+----+---------------------+
4 rows in set (0.00 sec)
--但以上数据并不正确,因为2019-03-20 00:00:00这一条数据并不符合timestampdiff(second,'2019-04-01 00:00:00',col2)>=0,但是返回的所有数据都符合timestampdiff(month,'2019-04-01 00:00:00',col2)=0,都在一个月之内。--那么,我们也看一下优化器到底做了什么:
mysql> desc select * from test where timestampdiff(second,'2019-04-01 00:00:00',col2)>=0 and timestampdiff(month,'2019-04-01 00:00:00',col2)=0;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | test  | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)mysql> show warnings;
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                    |
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `sam`.`test`.`id` AS `id`,`sam`.`test`.`col2` AS `col2` from `sam`.`test` where (timestampdiff(MONTH,'2019-04-01 00:00:00',`sam`.`test`.`col2`) = 0) |
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
--在show warnings中,我们可以看到,优化器把谓词条件timestampdiff(second,'2019-04-01 00:00:00',col2)>=0忽略掉了,只留下timestampdiff(month,'2019-04-01 00:00:00',col2)=0,所以才有上述的返回结果。--那么,优化器是怎样把谓词条件timestampdiff(second,'2019-04-01 00:00:00',col2)>=0忽略掉的呢,我们进一步追踪一下:
mysql> select * from information_schema.optimizer_trace\G
*************************** 1. row ***************************QUERY: select * from test where timestampdiff(second,'2019-04-01 00:00:00',col2)>=0 and timestampdiff(month,'2019-04-01 00:00:00',col2)=0TRACE: {"steps": [{"join_preparation": {"select#": 1,"steps": [{"expanded_query": "/* select#1 */ select `test`.`id` AS `id`,`test`.`col2` AS `col2` from `test` where ((timestampdiff(SECOND,'2019-04-01 00:00:00',`test`.`col2`) >= 0) and (timestampdiff(MONTH,'2019-04-01 00:00:00',`test`.`col2`) = 0))"}]}},{"join_optimization": {"select#": 1,"steps": [{"condition_processing": {"condition": "WHERE","original_condition": "((timestampdiff(SECOND,'2019-04-01 00:00:00',`test`.`col2`) >= 0) and (timestampdiff(MONTH,'2019-04-01 00:00:00',`test`.`col2`) = 0))","steps": [{"transformation": "equality_propagation","resulting_condition": "((timestampdiff(SECOND,'2019-04-01 00:00:00',`test`.`col2`) >= 0) and (timestampdiff(MONTH,'2019-04-01 00:00:00',`test`.`col2`) = 0))"},{"transformation": "constant_propagation","resulting_condition": "((0 >= 0) and (timestampdiff(MONTH,'2019-04-01 00:00:00',`test`.`col2`) = 0))"},{"transformation": "trivial_condition_removal","resulting_condition": "(timestampdiff(MONTH,'2019-04-01 00:00:00',`test`.`col2`) = 0)"}]}},{"substitute_generated_columns": {}},{"table_dependencies": [{"table": "`test`","row_may_be_null": false,"map_bit": 0,"depends_on_map_bits": []}]},{"ref_optimizer_key_uses": []},{"rows_estimation": [{"table": "`test`","table_scan": {"rows": 4,"cost": 1}}]},{"considered_execution_plans": [{"plan_prefix": [],"table": "`test`","best_access_path": {"considered_access_paths": [{"rows_to_scan": 4,"access_type": "scan","resulting_rows": 4,"cost": 1.8,"chosen": true}]},"condition_filtering_pct": 100,"rows_for_plan": 4,"cost_for_plan": 1.8,"chosen": true}]},{"attaching_conditions_to_tables": {"original_condition": "(timestampdiff(MONTH,'2019-04-01 00:00:00',`test`.`col2`) = 0)","attached_conditions_computation": [],"attached_conditions_summary": [{"table": "`test`","attached": "(timestampdiff(MONTH,'2019-04-01 00:00:00',`test`.`col2`) = 0)"}]}},{"refine_plan": [{"table": "`test`"}]}]}},{"join_execution": {"select#": 1,"steps": []}}]
}
MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0INSUFFICIENT_PRIVILEGES: 0
1 row in set (0.00 sec)
--注意transformation部分的constant_propagation,优化器将timestampdiff(SECOND,'2019-04-01 00:00:00',`test`.`col2`转化成了常数0,所以该谓词条件转化成了0>=0,条件成立,所以整个where部分取决于(timestampdiff(MONTH,'2019-04-01 00:00:00',`test`.`col2`) = 0)
--那么回顾前面第一个无法返回结果查询,优化器同样是将timestampdiff(SECOND,'2019-04-01 00:00:00',`test`.`col2`转化成了常数0,所以该谓词条件转化成了0>0,条件不成立,而对于and关系,该where条件恒为0,所以执行计划里会显示Impossible WHERE--这里,我们怀疑对于timestampdiff,当指定某个维度的时间差为0,例如上述例子的timestampdiff(MONTH,'xxxx',`test`.`col2`) = 0,那么,其他维度的时间差一律被MySQL认为是0,例如上述例子的minute
--下面用day,second来验证一下:
mysql> select * from test where timestampdiff(second,'2019-04-01 00:00:00',col2)>0 and timestampdiff(month,'2019-04-01 00:00:00',col2)=0 and timestampdiff(year,'2019-04-01 00:00:00',col2)=0;
Empty set (0.01 sec)mysql> select * from information_schema.optimizer_trace\G
*************************** 1. row ***************************QUERY: select * from test where timestampdiff(second,'2019-04-01 00:00:00',col2)>0 and timestampdiff(month,'2019-04-01 00:00:00',col2)=0 and timestampdiff(year,'2019-04-01 00:00:00',col2)=0TRACE: {"steps": [{"join_preparation": {"select#": 1,"steps": [{"expanded_query": "/* select#1 */ select `test`.`id` AS `id`,`test`.`col2` AS `col2` from `test` where ((timestampdiff(SECOND,'2019-04-01 00:00:00',`test`.`col2`) > 0) and (timestampdiff(MONTH,'2019-04-01 00:00:00',`test`.`col2`) = 0) and (timestampdiff(YEAR,'2019-04-01 00:00:00',`test`.`col2`) = 0))"}]}},{"join_optimization": {"select#": 1,"steps": [{"condition_processing": {"condition": "WHERE","original_condition": "((timestampdiff(SECOND,'2019-04-01 00:00:00',`test`.`col2`) > 0) and (timestampdiff(MONTH,'2019-04-01 00:00:00',`test`.`col2`) = 0) and (timestampdiff(YEAR,'2019-04-01 00:00:00',`test`.`col2`) = 0))","steps": [{"transformation": "equality_propagation","resulting_condition": "((timestampdiff(SECOND,'2019-04-01 00:00:00',`test`.`col2`) > 0) and (timestampdiff(MONTH,'2019-04-01 00:00:00',`test`.`col2`) = 0) and (timestampdiff(YEAR,'2019-04-01 00:00:00',`test`.`col2`) = 0))"},{"transformation": "constant_propagation","resulting_condition": "((0 > 0) and (timestampdiff(MONTH,'2019-04-01 00:00:00',`test`.`col2`) = 0) and (0 = 0))"},{"transformation": "trivial_condition_removal","resulting_condition": null}]}}],"empty_result": {"cause": "Impossible WHERE"}}},{"join_execution": {"select#": 1,"steps": []}}]
}
MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0INSUFFICIENT_PRIVILEGES: 0
1 row in set (0.00 sec)
--可以看到,谓词条件被转化成了((0 > 0) and (timestampdiff(DAY,'2019-04-01 00:00:00',`test`.`col2`) = 0) and (0 = 0)),然后无论是second还是year的条件,表中都是有符合的数据的。

timestampdiff的一个BUG相关推荐

  1. 软件测试培训分享:做软件测试工作如何清楚的描述一个bug

    一名合格的软件测试工程师是需要清楚的交代自己的工作任务的,必须要清楚的告诉技术员出现的bug,那么做软件测试工作如何清楚的描述一个bug呢?来看看下面的详细介绍. 软件测试培训分享:做软件测试工作如何 ...

  2. EnterLib PIAB又一个BUG?

    在<这是EnterLib PIAB的BUG吗?>一文中我们讨论了PIAB关于抽象基类的BUG,今天又发现了一个新的问题.问题的起因源于<IoC+AOP的简单实现>这篇文章,因为 ...

  3. 一个Bug能有多大影响:亏损30亿、致6人死亡、甚至差点毁灭世界...

    欢迎关注方志朋的博客,回复"666"获面试宝典 作者:博雯   来源:量子位(QbitAI) 一个Bug就地蒸发5亿美元: 软件设计层面出Bug致6人死亡: DeBug不成功直接世 ...

  4. 从一个Bug开始,重新认识一个强大的 Gson

    点击上方"方志朋",选择"置顶公众号" 技术文章第一时间送达! 作者:Mafly, 地址:www.cnblogs.com/mafly/p/gson.html 从 ...

  5. 关于MySQL count(distinct) 逻辑的另一个bug

    背景          上一篇博文(链接)介绍了count distinct的一个bug.解决完以后发现客户的SQL语句仍然返回错误结果(0), 再查原因,发现了另外一个bug.也就是说,这个SQL语 ...

  6. sdcms的一个bug,总是提示,该文件不允许被上传

    之前通过sdcms做过一个网站,最近在上传文件时,总是提示,该文件不允许被上传.于是跟踪了一下,发现了一个bug 上传附近是通过admin目录下的Sdcms_Editor_Up.asp来提交的,当文件 ...

  7. CSSFriendlyAdapter 的一个Bug

    因为要使用树控件的客户端脚本功能,发行asp.net 2.0中默认提供的树控件,并没有开放这方面的接口.要实现客户端的编程还是很有难度的. 查找了一些第三方的控件,不是需要收费,就是功能想对较弱. 后 ...

  8. QQ超市模拟排配2D版1.13 (XNA4.0) (修正双格货架移动的一个bug和3-5地图)

    抱歉,更新了一个地图-- 下载地址:(版本过期了,请下新版) 1.13:更新日期:2012-3-22 更新3店5口地图错误问题.启动程序前请手动删除旧版地图数据. 地址:C:\(我的文档路径)\Sav ...

  9. VS2002 与 IIS6.0的一个bug

    今天遇到一个问题,就是在win2003上用vs2002打开一个asp.net project.总是提示: The default Web access mode for this project is ...

最新文章

  1. java中调用python
  2. Linux中SysRq的使用[zt]
  3. nslookup命令dns请求超时_网络工程师之nslookup命令
  4. 阿里云叔同:以容器为代表的云原生技术,已成为释放云价值的最短路径
  5. 彻底弄懂dalvik字节码【二】
  6. 一个简单的小技巧,监控网页所有动态标签创建的调用处
  7. python有趣的面试题_python面试题目
  8. Flink 消息聚合处理方案
  9. DWA泊车算法的实现
  10. 738. 单调递增的数字(JavaScript)
  11. 给技术型创业者的几点建议
  12. 【情感分析】华为云细粒度文本情感分析及应用
  13. php中对象是引用类型吗?
  14. SCM供应链管理的背景及意义
  15. 0704第五讲异常处理
  16. 计算机在欢迎进不到桌面,电脑一直在欢迎界面进不去怎么解决_电脑开机一直卡在欢迎界面怎么办-win7之家...
  17. 插入(希尔)排序时间、空间复杂度
  18. Jetson 配置中文环境,中文输入法,安装QQ
  19. 【Scratch-动作模块】滑行指令
  20. 深度学习(9):FastFCN论文翻译与学习

热门文章

  1. Java常用类练习01
  2. 密码控晒稀奇密码大开眼界 文艺密码PK科学密码
  3. NYOJ-203 三国志
  4. 百度网盘可以自动备份电脑文件吗?
  5. 【Linux内核】Linux内核介绍
  6. 本地链接 云数据库mysql_云数据库本地连接
  7. 无法定位程序输入点于动态链接库上的原因
  8. 网购巨头京东赚钱揭秘,是自寻死路还是生财有道?
  9. 三态缓冲器的工作原理
  10. POI读取doc、docx文件