MySQL令人咋舌的隐式转换

代码 代码 1401 人阅读 | 0 人回复

<
导读
     
            做者缓朝明,     MySQL DBA,知数堂教员。热中于数据库劣化,主动化运维及数据库周边东西开辟,对     MySQL源码有必然的爱好         
     本文倡议横屏寓目,结果更佳   



1、成绩形貌


  1. root@mysqldb 22:12:  [xucl]> show create table t1\G
  2. *************************** 1. row ***************************
  3.        Table: t1
  4. Create Table: CREATE TABLE `t1` (
  5.   `id` varchar(255) DEFAULT NULL
  6. ) ENGINE=InnoDB DEFAULT CHARSET=utf8
  7. 1 row in set (0.00 sec)

  8. root@mysqldb 22:19:  [xucl]> select * from t1;
  9. +--------------------+
  10. | id                 |
  11. +--------------------+
  12. | 204027026112927605 |
  13. | 204027026112927603 |
  14. | 2040270261129276   |
  15. | 2040270261129275   |
  16. | 100                |
  17. | 101                |
  18. +--------------------+
  19. 6 rows in set (0.00 sec)
复造代码
奇异的征象:
  1. root@mysqldb 22:19:  [xucl]> select * from t1 where id=204027026112927603;
  2. +--------------------+
  3. | id                 |
  4. +--------------------+
  5. | 204027026112927605 |
  6. | 204027026112927603 |
  7. +--------------------+
  8. 2 rows in set (0.00 sec)
复造代码

MySQL使人咋舌的隐式转换

MySQL使人咋舌的隐式转换

甚么鬼,明显查的是204027026112927603,为何204027026112927605也出去了

2、源码注释

仓库挪用干系以下所示:

MySQL使人咋舌的隐式转换

MySQL使人咋舌的隐式转换


此中JOIN::exec()是施行的进口,Arg_comparator::compare_real()是停止等值判定的函数,其界说以下
  1. int Arg_comparator::compare_real()
  2. {
  3.   /*
  4.     Fix yet another manifestation of Bug#2338. &#39;Volatile&#39; will instruct
  5.     gcc to flush double values out of 80-bit Intel FPU registers before
  6.     performing the comparison.
  7.   */
  8.   volatile double val1, val2;
  9.   val1= (*a)->val_real();
  10.   if (!(*a)->null_value)
  11.   {
  12.     val2= (*b)->val_real();
  13.     if (!(*b)->null_value)
  14.     {
  15.       if (set_null)
  16.         owner->null_value= 0;
  17.       if (val1 < val2)  return -1;
  18.       if (val1 == val2) return 0;
  19.       return 1;
  20.     }
  21.   }
  22.   if (set_null)
  23.     owner->null_value= 1;
  24.   return -1;
  25. }
复造代码
比力步伐以下图所示,逐止读与t1表的id列放进val1,而常量204027026112927603存正在于cache中,范例为double范例(2.0402702611292762E+17),以是到那里传值给val2后val2=2.0402702611292762E+17。

MySQL使人咋舌的隐式转换

MySQL使人咋舌的隐式转换


当扫描到第一止时,204027026112927605转成doule的值为2.0402702611292762e17,等式建立,断定为契合前提的止,持续往下扫描,同理204027026112927603也一样契合

MySQL使人咋舌的隐式转换

MySQL使人咋舌的隐式转换


怎样检测string范例的数字转成doule范例能否溢出呢?那里颠末测试,当数字超越16位当前,转成double范例便曾经禁绝确了,比方20402702611292711会暗示成20402702611292712(如图中val1)

MySQL使人咋舌的隐式转换

MySQL使人咋舌的隐式转换

MySQL使人咋舌的隐式转换

MySQL使人咋舌的隐式转换

MySQL string转成double的界说函数以下:


  1. {
  2.   char buf[DTOA_BUFF_SIZE];
  3.   double res;
  4.   DBUG_ASSERT(end != NULL && ((str != NULL && *end != NULL) ||
  5.                               (str == NULL && *end == NULL)) &&
  6.               error != NULL);

  7.   res= my_strtod_int(str, end, error, buf, sizeof(buf));
  8.   return (*error == 0) ? res : (res < 0 ? -DBL_MAX : DBL_MAX);
  9. }
复造代码
实正转换函数my_strtod_int地位正在dtoa.c(太庞大了,简朴揭个正文吧)
  1. /*
  2.   strtod for IEEE--arithmetic machines.

  3.   This strtod returns a nearest machine number to the input decimal
  4.   string (or sets errno to EOVERFLOW). Ties are broken by the IEEE round-even
  5.   rule.

  6.   Inspired loosely by William D. Clinger&#39;s paper "How to Read Floating
  7.   Point Numbers Accurately" [Proc. ACM SIGPLAN &#39;90, pp. 92-101].

  8.   Modifications:

  9.    1. We only require IEEE (not IEEE double-extended).
  10.    2. We get by with floating-point arithmetic in a case that
  11.      Clinger missed -- when we&#39;re computing d * 10^n
  12.      for a small integer d and the integer n is not too
  13.      much larger than 22 (the maximum integer k for which
  14.      we can represent 10^k exactly), we may be able to
  15.      compute (d*10^k) * 10^(e-k) with just one roundoff.
  16.    3. Rather than a bit-at-a-time adjustment of the binary
  17.      result in the hard case, we use floating-point
  18.      arithmetic to determine the adjustment to within
  19.      one bit; only in really hard cases do we need to
  20.      compute a second residual.
  21.    4. Because of 3., we don&#39;t need a large table of powers of 10
  22.      for ten-to-e (just some small tables, e.g. of 10^k
  23.      for 0 <= k <= 22).
  24. */
复造代码
结果契合预期,而正在本例中,准确的写法该当是
  1. root@mysqldb 23:30:  [xucl]> select * from t1 where id=2040270261129276;
  2. +------------------+
  3. | id               |
  4. +------------------+
  5. | 2040270261129276 |
  6. +------------------+
  7. 1 row in set (0.00 sec)

  8. root@mysqldb 23:30:  [xucl]> select * from t1 where id=101;
  9. +------+
  10. | id   |
  11. +------+
  12. | 101  |
  13. +------+
  14. 1 row in set (0.00 sec)
复造代码
3、结论

  • 制止发作隐式范例转换,隐式转换的范例次要有字段范例纷歧致、in参数包罗多个范例、字符散范例或校正划定规矩纷歧致等
  • 隐式范例转换能够招致没法利用索引、查询结果禁绝确等,因而正在利用时必需认真鉴别
  • 数字范例的倡议正在字段界说时便界说为int大要bigint,表联系关系时联系关系字段必需连结范例、字符散、校正划定规矩皆分歧
  • 最初揭一下民网关于隐式范例转换的阐明吧
  1. root@mysqldb 22:19:  [xucl]> select * from t1 where id=&#39;204027026112927603&#39;;
  2. +--------------------+
  3. | id                 |
  4. +--------------------+
  5. | 204027026112927603 |
  6. +--------------------+
  7. 1 row in set (0.01 sec)
复造代码




参考文章

1、聊聊 隐式转换
2、Type Conversion in Expression Evaluation:https://dev.mysql.com/doc/refman/8.0/en/type-conversion.html
感激八怪的友谊指点,念进修更多源码内乱容,激烈保举一下八怪的专栏《深化了解MySQL主从道理》

END


面击下图小法式定阅
《深化了解MySQL主从道理32讲》专栏
可理解更多八怪手艺文章

MySQL使人咋舌的隐式转换

MySQL使人咋舌的隐式转换


MySQL使人咋舌的隐式转换

MySQL使人咋舌的隐式转换




         

MySQL使人咋舌的隐式转换

MySQL使人咋舌的隐式转换
      

      
   
      


免责声明:假如进犯了您的权益,请联络站少,我们会实时删除侵权内乱容,感谢协作!
1、本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,按照目前互联网开放的原则,我们将在不通知作者的情况下,转载文章;如果原文明确注明“禁止转载”,我们一定不会转载。如果我们转载的文章不符合作者的版权声明或者作者不想让我们转载您的文章的话,请您发送邮箱:Cdnjson@163.com提供相关证明,我们将积极配合您!
2、本网站转载文章仅为传播更多信息之目的,凡在本网站出现的信息,均仅供参考。本网站将尽力确保所提供信息的准确性及可靠性,但不保证信息的正确性和完整性,且不对因信息的不正确或遗漏导致的任何损失或损害承担责任。
3、任何透过本网站网页而链接及得到的资讯、产品及服务,本网站概不负责,亦不负任何法律责任。
4、本网站所刊发、转载的文章,其版权均归原作者所有,如其他媒体、网站或个人从本网下载使用,请在转载有关文章时务必尊重该文章的著作权,保留本网注明的“稿件来源”,并自负版权等法律责任。
回复 关闭延时

使用道具 举报

 
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则