mysql with ties_MySQL令人咋舌的隐式转换
二、源码解释
堆栈调用关系如下所示:
其中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令人咋舌的隐式转换相关推荐
- mysql to double_MySQL令人咋舌的隐式转换 - 惊觉...
导读 作者徐晨亮, MySQL DBA,知数堂学员.热衷于数据库优化,自动化运维及数据库周边工具开发,对 MySQL源码有一定的兴趣 本文建议横屏观看,效果更佳 一.问题描述 [email prote ...
- MySQL令人咋舌的隐式转换
一.问题描述 root@mysqldb 22:12: [xucl]> show create table t1\G *************************** 1. row **** ...
- MySQL和Oracle中的隐式转换
今天在处理一个问题的时候,需要根据其他部门提供的sql语句对一个表中的数据进行了筛查. 语句类似下面的形式 > SELECT MAX_LEVEL,LOGOUT_TIME,CURRENT_DATE ...
- 在将varchar值id转换为int时失败_MySQL令人咋舌的隐式转换
导读 作者徐晨亮,MySQL DBA,知数堂学员.热衷于数据库优化,自动化运维及数据库周边工具开发,对MySQL源码有一定的兴趣 本文建议横屏观看,效果更佳 一.问题描述 root@mysqldb 2 ...
- MySQL中varchar类型字段隐式转换造成多删除数据
例如一个表中字段是varchar类型: desc test; +-------+-------------+------+-----+---------+----------------+ | Fie ...
- mysql 隐式失误_评“MySQL 隐式转换引起的执行结果错误”
今天看到一篇关于MySQL隐式转换引发执行结果错误的文章: ====================================================================== ...
- mysql数据库隐式表_详解MySQL数据库常见的索引问题:无索引,隐式转换,附实例说明...
概述 在这些年的工作之中,由于SQL问题导致的数据库故障层出不穷,而索引问题是SQL问题中出现频率最高的,常见的索引问题包括:无索引,隐式转换. 索引问题 1.无索引 当数据库中出现访问表的SQL无索 ...
- mysql隐式转换造成索引失效的事故总结
隐式转换导致索引失效.这一点应当引起重视.也是开发中经常会犯的错误. 由于表的字段tu_mdn定义为varchar2(20),但在查询时把该字段作为number类型以where条件传给mysql,这样 ...
- MySQL 隐式转换 字符串和整型说明
MySQL 隐式转换 字段类型定义 CREATE TABLE `user` (`id` int(10) NOT NULL AUTO_INCREMENT COMMENT '编号',/* ...... * ...
最新文章
- TDSQL在微众银行的大规模实践之路
- char string 区别
- 陆基制导系统地面站布设策略
- win10打开程序响应很慢_小程序商城打开加载很慢?你上传的图片是不是太大了,压缩一下吧!...
- 太好了,一分钟带你分清Python的模块、库、包有什么联系和区别?
- Windows中获取和设置系统日期时间的C程序
- vector clone_Java Vector clone()方法与示例
- Windows下如何查看某个端口被谁占用并强制关闭
- 还原哈希密码工具(hash、md5)
- Markdown 基础语法与常见问题总结
- LeetCode(700)——二叉搜索树中的搜索(JavaScript)
- servlet精华讲解
- CSMA协议:改进的ALOHA协议
- 实现数据库连接池druid的工具类
- 安川服务器显示ab32,安川驱动器维修常见报警代码及维修方法
- 我们与专家讨论了JavaScript –文字记录
- 影视解说短视频如何配音?三个文字转语音小技巧,配音其实也不难
- Clion~Clion常用配置和插件
- Set的创建和遍历方法
- 删除所有奇数顺序表c语言,如何删除列表中的所有奇数序数项?