`

mysql隐式转换导致查询语句不能走索引分析

阅读更多

        如下两条SQL语句,一个不走索引,一个走索引。


        在这里,为什么第一条语句未加单引号就不走索引,而第二条加单引号的就走索引呢?

原因是第一条语句由于类型不匹配,MySQL会做隐式的类型转换,都将其转换为浮点数在比较;而第二条语句因为类型一致,不会转浮点数,就是字符串之间的比较,所以就能正常走索引。

一.进一步了解隐式转换

对于第一种情况:

        比如where string = 1;需要将索引中的字符串转换成浮点数,但是由于'1','1','1a'都会比转化成1,故MySQL无法使用索引只能进行全表扫描,故造成了慢查询的产生。

        这里并不是因为字符串字段值转换成了浮点数?而'1',' 1','1a'转换成1,是整数,类型不匹配导致只能进行全表扫描,而是因为都转换浮点数了,'1','1','1a'本来三个不同的值都是相同的值了,还是打破了有序的规则。

mysql> SELECT CAST('  1' AS SIGNED)=1;
+-------------------------+
| CAST('  1' AS SIGNED)=1 |
+-------------------------+
|                       1 |
+-------------------------+
1 row in set (0.00 sec)
 
mysql> SELECT CAST('  1a' AS SIGNED)=1;
+--------------------------+
| CAST('  1a' AS SIGNED)=1 |
+--------------------------+
|                        1 |
+--------------------------+
1 row in set, 1 warning (0.00 sec)
 
mysql> SELECT CAST('1' AS SIGNED)=1;
+-----------------------+
| CAST('1' AS SIGNED)=1 |
+-----------------------+
|                     1 |
+-----------------------+
1 row in set (0.00 sec)

        同时需要注意一点,由于都会转换成浮点数进行比较,而浮点数只有53bit,故当超过最大值的时候,比较会出现问题。

对于第二种情况:

        由于索引建立在int的基础上,而将纯数字的字符串可以百分百转换成数字,故可以使用到索引,虽然也会进行一定的转换,消耗一定的资源,但是最终仍然使用了索引,不会产生慢查询。

mysql> select CAST( '30' as SIGNED) = 30;
+----------------------------+
| CAST( '30' as SIGNED) = 30 |
+----------------------------+
|                          1 |
+----------------------------+
1 row in set (0.00 sec)

 

二.官方解释

        为什么一个小小的''为什么会有这么大的影响呢?根本原因是因为MySQL在对文本类型和数字类型进行比较的时候会进行隐式的类型转换。以下是5.5官方手册的说明:

If both arguments in a comparison operation are strings, they are compared as strings.
两个参数都是字符串,会按照字符串来比较,不做类型转换。
If both arguments are integers, they are compared as integers.
两个参数都是整数,按照整数来比较,不做类型转换。
Hexadecimal values are treated as binary strings if not compared to a number.
十六进制的值和非数字做比较时,会被当做二进制串。
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. Note that 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.
有一个参数是 TIMESTAMP 或 DATETIME,并且另外一个参数是常量,常量会被转换为 timestamp
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.
有一个参数是 decimal 类型,如果另外一个参数是 decimal 或者整数,会将整数转换为 decimal 后进行比较,如果另外一个参数是浮点数,则会把 decimal 转换为浮点数进行比较
In all other cases, the arguments are compared as floating-point (real) numbers.
所有其他情况下,两个参数都会被转换为浮点数再进行比较

        根据以上的说明,当where条件之后的值的类型和表结构不一致的时候,MySQL会做隐式的类型转换,都将其转换为浮点数在比较。

  • 大小: 94 KB
分享到:
评论

相关推荐

    mysql查询不走索引及解决方法

    mysql查询,通过explain 分析,没有利用到索引,查询效率不高等出现的问题。

    mysql中or是否走索引详解

    NULL 博文链接:https://bugyun.iteye.com/blog/2242094

    Mysql 5.6 隐式转换导致的索引失效和数据不准确的问题

    在一次进行SQl查询时,我试着对where条件中vachar类型的字段去掉单引号查询,这个时候发现这条本应该很快的语句竟然很慢。这个varchar字段有一个复合索引。其中的总条数有58989,甚至不加单引号查出来的数据不是...

    MySQL的or、in、union与索引优化

    一:union all 肯定是能够命中索引的 二:简单的in能够命中索引 三:对于or,新版的MySQL能够命中索引 四、对于!=,负向查询肯定不能命中索引 五、其他方案

    MySQL中因字段字符集不同导致索引不能命中的解决方法

    索引用于快速找出在某个列中有一特定值的行,不使用索引,MySQL必须从第一条记录开始读完整个表,直到找出相关的行,表越大,查询数据所花费的时间就越多,如果表中查询的列有一个索引,MySQL能够快速到达一个位置去...

    MySQL前缀索引导致的慢查询分析总结

    前缀索引,并不是一个万能药,他的确可以帮助我们对一个写过长的字段上建立索引。但也会导致排序(order by ,group by)查询上都是无法使用前缀索引的

    Mysql慢查询优化方法及优化原则

    1、日期大小的比较,传到xml中的日期格式要符合’yyyy-MM-dd’,这样才能走索引,如:’yyyy’改为’yyyy-MM-dd’,’yyyy-MM’改为’yyyy-MM-dd’【这样MYSQL会转换为日期类型】 2、条件语句中无论是等于、还是大于...

    MySQL Order By索引优化方法

    在一些情况下,MySQL可以直接使用索引来满足一个 ORDER BY 或 GROUP BY 子句而无需做额外的排序

    MySQL 函数索引的优化方案

    很多开发人员在使用MySQL时经常会在部分列上进行函数计算等,导致无法走索引,在数据量大的时候,查询效率低下。针对此种情况本文从MySQL5.7 及MySQL8.0中分别进行不同方式的优化。 1、 MySQL5.7 MySQL5.7版本中不...

    oracel 分区表索引失效的问题

    讲解oracle分区表的索引问题,有具体的例子和实验分析

    MYSQL中常用的强制性操作(例如强制索引)

    对于经常使用oracle的朋友可能知道,oracle的hint功能种类很多,对于优化sql语句提供了很多方法。同样,在mysql里,也有类似的hint功能。

    MySQL去重该使用distinct还是group by?

    关于group by 与distinct 性能对比:网上结论如下,不走索引少量数据distinct性能更好,大数据量group by 性能好,走索引group by性能好。走索引时分组种类少distinct快。关于网上的结论做一次验证。 准备阶段屏蔽...

    Oracle使用强制索引的方法与注意事项

    在一些场景下,可能ORACLE不会自动走索引,这时候,如果对业务清晰,可以尝试使用强制索引,测试查询语句的性能。 以EMP表为例: 先在EMP表中建立唯一索引,如图。 普通搜索: SELECT * FROM EMP T 查看执行计划:...

    oracle 三种索引

    oracle 三种索引的简单描述,位图、B树、全文索引。

    ORACLE索引介绍与高性能SQL优化

    ORACLE索引介绍与高性能SQL优化的相关知识

    Oracle索引

    关于Oracle索引的详细介绍,索引的基本概念,怎么创建单列、符合索引。

    MYSQL字符串强转的方法示例

    注意:需转换的类型必须是left join 后表的字段,否则不走索引 因为联表字段类型不一致,所以不走索引 select t.* from A tleft join B t1 on t.id = t1.id  第一种转换类型 select t.* from A tleft join B t1 ...

    SQL查询安全性及性能优化

     没有建立索引,或者SQL没有走索引。在千万级数据的表上建索引是很有必要的。  SQL过于复杂,过长的SQL语句满足程序需求但是影响性能。子查询嵌套过多对性能有影响,查询关联的表特别多也影响性能  频繁访问...

Global site tag (gtag.js) - Google Analytics