二、源码解释

堆栈调用关系如下所示:

其中JOIN::exec()是执行的入口,Arg_comparator::compare_real()是进行等值判断的函数,其定义如下

int Arg_comparator::compare_real()

{

/*

Fix yet another manifestation of Bug#2338. 'Volatile' will instruct

gcc to flush double values out of 80-bit Intel FPU registers before

performing the comparison.

*/

volatile double val1, val2;

val1= (*a)->val_real();

if (!(*a)->null_value)

{

val2= (*b)->val_real();

if (!(*b)->null_value)

{

if (set_null)

owner->null_value= 0;

if (val1 < val2) return -1;

if (val1 == val2) return 0;

return 1;

}

}

if (set_null)

owner->null_value= 1;

return -1;

}

比较步骤如下图所示,逐行读取t1表的id列放入val1,而常量204027026112927603存在于cache中,类型为double类型(2.0402702611292762E+17),所以到这里传值给val2后val2=2.0402702611292762E+17。

当扫描到第一行时,204027026112927605转成doule的值为2.0402702611292762e17,等式成立,判定为符合条件的行,继续往下扫描,同理204027026112927603也同样符合

如何检测string类型的数字转成doule类型是否溢出呢?这里经过测试,当数字超过16位以后,转成double类型就已经不准确了,例如20402702611292711会表示成20402702611292712(如图中val1)

MySQL string转成double的定义函数如下:

{

char buf[DTOA_BUFF_SIZE];

double res;

DBUG_ASSERT(end != NULL && ((str != NULL && *end != NULL) ||

(str == NULL && *end == NULL)) &&

error != NULL);

res= my_strtod_int(str, end, error, buf, sizeof(buf));

return (*error == 0) ? res : (res < 0 ? -DBL_MAX : DBL_MAX);

}

真正转换函数my_strtod_int位置在dtoa.c(太复杂了,简单贴个注释吧)

/*

strtod for IEEE--arithmetic machines.

This strtod returns a nearest machine number to the input decimal

string (or sets errno to EOVERFLOW). Ties are broken by the IEEE round-even

rule.

Inspired loosely by William D. Clinger's paper "How to Read Floating

Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].

Modifications:

1. We only require IEEE (not IEEE double-extended).

2. We get by with floating-point arithmetic in a case that

Clinger missed -- when we're computing d * 10^n

for a small integer d and the integer n is not too

much larger than 22 (the maximum integer k for which

we can represent 10^k exactly), we may be able to

compute (d*10^k) * 10^(e-k) with just one roundoff.

3. Rather than a bit-at-a-time adjustment of the binary

result in the hard case, we use floating-point

arithmetic to determine the adjustment to within

one bit; only in really hard cases do we need to

compute a second residual.

4. Because of 3., we don't need a large table of powers of 10

for ten-to-e (just some small tables, e.g. of 10^k

for 0 <= k <= 22).

*/

既然是这样,我们测试下没有溢出的案例

root@mysqldb 23:30: [xucl]> select * from t1 where id=2040270261129276;

+------------------+

| id |

+------------------+

| 2040270261129276 |

+------------------+

1 row in set (0.00 sec)

root@mysqldb 23:30: [xucl]> select * from t1 where id=101;

+------+

| id |

+------+

| 101 |

+------+

1 row in set (0.00 sec)

结果符合预期,而在本例中,正确的写法应当是

root@mysqldb 22:19: [xucl]> select * from t1 where id='204027026112927603';

+--------------------+

| id |

+--------------------+

| 204027026112927603 |

+--------------------+

1 row in set (0.01 sec)

三、结论

避免发生隐式类型转换,隐式转换的类型主要有字段类型不一致、in参数包含多个类型、字符集类型或校对规则不一致等

隐式类型转换可能导致无法使用索引、查询结果不准确等,因此在使用时必须仔细甄别

数字类型的建议在字段定义时就定义为int或者bigint,表关联时关联字段必须保持类型、字符集、校对规则都一致

最后贴一下官网对于隐式类型转换的说明吧

1、If one or both arguments are NULL, the result of the comparison is NULL, except for the NULL-safe

<=> equality comparison operator. For NULL <=> NULL, the result is true. No conversion is needed.

2、If both arguments in a comparison operation are strings, they are compared as strings.

3、If both arguments are integers, they are compared as integers.

4、Hexadecimal values are treated as binary strings if not compared to a number.

5、If one of the arguments is a TIMESTAMP or DATETIME column and the other argument is a

constant, the constant is converted to a timestamp before the comparison is performed. This is

done to be more ODBC-friendly. This is not done for the arguments to IN(). To be safe, always

use complete datetime, date, or time strings when doing comparisons. For example, to achieve best

results when using BETWEEN with date or time values, use CAST() to explicitly convert the values to

the desired data type.

A single-row subquery from a table or tables is not considered a constant. For example, if a subquery

returns an integer to be compared to a DATETIME value, the comparison is done as two integers.

The integer is not converted to a temporal value. To compare the operands as DATETIME values,

use CAST() to explicitly convert the subquery value to DATETIME.

6、If one of the arguments is a decimal value, comparison depends on the other argument. The

arguments are compared as decimal values if the other argument is a decimal or integer value, or as

floating-point values if the other argument is a floating-point value.

7、In all other cases, the arguments are compared as floating-point (real) numbers.

参考文章

2、Type Conversion in Expression Evaluation:https://dev.mysql.com/doc/refman/8.0/en/type-conversion.html

感谢八怪的友情指导,想学习更多源码内容,强烈推荐一下八怪的专栏《深入理解MySQL主从原理》

END

点击下图小程序订阅《深入理解MySQL主从原理32讲》专栏可了解更多八怪技术文章

扫码加入MySQL技术Q群

(群号:793818397)

mysql with ties_MySQL令人咋舌的隐式转换相关推荐

  1. mysql to double_MySQL令人咋舌的隐式转换 - 惊觉...

    导读 作者徐晨亮, MySQL DBA,知数堂学员.热衷于数据库优化,自动化运维及数据库周边工具开发,对 MySQL源码有一定的兴趣 本文建议横屏观看,效果更佳 一.问题描述 [email prote ...

  2. MySQL令人咋舌的隐式转换

    一.问题描述 root@mysqldb 22:12: [xucl]> show create table t1\G *************************** 1. row **** ...

  3. MySQL和Oracle中的隐式转换

    今天在处理一个问题的时候,需要根据其他部门提供的sql语句对一个表中的数据进行了筛查. 语句类似下面的形式 > SELECT MAX_LEVEL,LOGOUT_TIME,CURRENT_DATE ...

  4. 在将varchar值id转换为int时失败_MySQL令人咋舌的隐式转换

    导读 作者徐晨亮,MySQL DBA,知数堂学员.热衷于数据库优化,自动化运维及数据库周边工具开发,对MySQL源码有一定的兴趣 本文建议横屏观看,效果更佳 一.问题描述 root@mysqldb 2 ...

  5. MySQL中varchar类型字段隐式转换造成多删除数据

    例如一个表中字段是varchar类型: desc test; +-------+-------------+------+-----+---------+----------------+ | Fie ...

  6. mysql 隐式失误_评“MySQL 隐式转换引起的执行结果错误”

    今天看到一篇关于MySQL隐式转换引发执行结果错误的文章: ====================================================================== ...

  7. mysql数据库隐式表_详解MySQL数据库常见的索引问题:无索引,隐式转换,附实例说明...

    概述 在这些年的工作之中,由于SQL问题导致的数据库故障层出不穷,而索引问题是SQL问题中出现频率最高的,常见的索引问题包括:无索引,隐式转换. 索引问题 1.无索引 当数据库中出现访问表的SQL无索 ...

  8. mysql隐式转换造成索引失效的事故总结

    隐式转换导致索引失效.这一点应当引起重视.也是开发中经常会犯的错误. 由于表的字段tu_mdn定义为varchar2(20),但在查询时把该字段作为number类型以where条件传给mysql,这样 ...

  9. MySQL 隐式转换 字符串和整型说明

    MySQL 隐式转换 字段类型定义 CREATE TABLE `user` (`id` int(10) NOT NULL AUTO_INCREMENT COMMENT '编号',/* ...... * ...

最新文章

  1. TDSQL在微众银行的大规模实践之路
  2. char string 区别
  3. 陆基制导系统地面站布设策略
  4. win10打开程序响应很慢_小程序商城打开加载很慢?你上传的图片是不是太大了,压缩一下吧!...
  5. 太好了,一分钟带你分清Python的模块、库、包有什么联系和区别?
  6. Windows中获取和设置系统日期时间的C程序
  7. vector clone_Java Vector clone()方法与示例
  8. Windows下如何查看某个端口被谁占用并强制关闭
  9. 还原哈希密码工具(hash、md5)
  10. Markdown 基础语法与常见问题总结
  11. LeetCode(700)——二叉搜索树中的搜索(JavaScript)
  12. servlet精华讲解
  13. CSMA协议:改进的ALOHA协议
  14. 实现数据库连接池druid的工具类
  15. 安川服务器显示ab32,安川驱动器维修常见报警代码及维修方法
  16. 我们与专家讨论了JavaScript –文字记录
  17. 影视解说短视频如何配音?三个文字转语音小技巧,配音其实也不难
  18. Clion~Clion常用配置和插件
  19. Set的创建和遍历方法
  20. 删除所有奇数顺序表c语言,如何删除列表中的所有奇数序数项?

热门文章

  1. empire-web可视化
  2. docker搭建pwn环境
  3. 重游java(猜数和逛街)
  4. 反编译apk文件教程(查看java代码篇)
  5. svn回退到历史版本
  6. SSD 通俗易懂介绍
  7. ACM入门之【最小生成树】
  8. 项目: 图片放大缩小。
  9. RabbitMQ路由模式
  10. Struts2的文件目录