美文网首页
[转载]Mysql 隐式转换

[转载]Mysql 隐式转换

作者: zshanjun | 来源:发表于2017-06-28 17:29 被阅读40次

之前有用户很不解:SQL语句非常简单,就是select * from test_1 where user_id=1 这种类型,而且user_id上已经建立索引了,怎么还是查询很慢?

test_1的表结构:


CREATE TABLE `test_1` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `user_id` varchar(30) NOT NULL,

  `name` varchar(30) DEFAULT NULL,

  PRIMARY KEY (`id`),

  KEY `idx_user_id` (`user_id`)

) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

查看执行计划,可以看出进行了全表扫描,并没有用上user_id的索引。


mysql> explain select * from test_1 where user_id=1;

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

| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows | Extra       |

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

|  1 | SIMPLE      | test_1 | ALL  | idx_user_id   | NULL | NULL    | NULL |    3 | Using where |

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

1 row in set (0.01 sec)

仔细看下表结构,user_id的字段类型: user_id varchar(30) NOT NULL,

而用户传入的是int,这里会有一个隐式转换的问题。隐式转换会导致全表扫描。

把输入改成字符串类型,执行计划如下,这样就会很快了。


mysql> explain select * from test_1 where user_id='1';

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

| id | select_type | table  | type | possible_keys | key         | key_len | ref   | rows | Extra       |

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

|  1 | SIMPLE      | test_1 | ref  | idx_user_id   | idx_user_id | 92      | const |    1 | Using where |

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

1 row in set (0.00 sec)

此外,还需要注意的是:

数字类型的0001等价于1

字符串的0001和1不等价


mysql> select * from test_1;

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

| id | user_id | name |

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

|  1 | 0001    | kate |

|  2 | 1101    | Jim  |

|  3 | 1       | Jim  |

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

3 rows in set (0.01 sec)

 

 

mysql> select * from test_1 where user_id=1;

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

| id | user_id | name |

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

|  1 | 0001    | kate |

|  3 | 1       | Jim  |

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

2 rows in set (0.00 sec)

 

mysql> select * from test_1 where user_id='1';

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

| id | user_id | name |

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

|  3 | 1       | Jim  |

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

1 row in set (0.00 sec)


如果表定义的是int字段,传入的是字符串,则不会发生隐式转换。

看下面的测试:


CREATE TABLE `test_2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`name` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

 

mysql> explain select * from test_2 where user_id=1;
+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------+
| 1 | SIMPLE | test_2 | ref | idx_user_id | idx_user_id | 4 | const | 2 | |
+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------+
1 row in set (0.00 sec)

mysql> explain select * from test_2 where user_id='1';
+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------+
| 1 | SIMPLE | test_2 | ref | idx_user_id | idx_user_id | 4 | const | 2 | |
+----+-------------+--------+------+---------------+-------------+---------+-------+------+-------+
1 row in set (0.00 sec)


mysql隐式转换规则:
a. 两个参数至少有一个是 NULL 时,比较的结果也是 NULL,例外是使用 <=> 对两个 NULL 做比较时会返回 1,这两种情况都不需要做类型转换
b. 两个参数都是字符串,会按照字符串来比较,不做类型转换
c. 两个参数都是整数,按照整数来比较,不做类型转换
d. 十六进制的值和非数字做比较时,会被当做二进制串
e. 有一个参数是 TIMESTAMP 或 DATETIME,并且另外一个参数是常量,常量会被转换为 timestamp
f. 有一个参数是 decimal 类型,如果另外一个参数是 decimal 或者整数,会将整数转换为 decimal 后进行比较,如果另外一个参数是浮点数,则会把 decimal 转换为浮点数进行比较
g. 所有其他情况下,两个参数都会被转换为浮点数再进行比较

开发人员可能知道存在这么一个隐式类型转换的坑,但却又经常不注意,所以干脆无需记住那么多规则,该什么类型就与什么类型比较。


参考网站:

相关文章

  • [转载]Mysql 隐式转换

    之前有用户很不解:SQL语句非常简单,就是select * from test_1 where user_id=1...

  • MySQL之隐式转换

    MySQL之隐式转换 inexplicit conversion 之前也总给业务优化SQL,隐式转换也非常常见,但...

  • scala中的隐式-scala02

    发现这个坐着写的太好了,转载:scala学习 - 隐式转换和隐式参数 - 简书

  • mysql隐式转换

    mysql隐式转换 (版本 5.7) 表结构如下: 添加的几条数据 字段类型varchar, 查询条件为int和s...

  • mysql隐式转换

    隐式转化把字符串转为了double类型。 1.当字段是数值类型时,加引号或者不加引号都不影响索引的使用。 2.当字...

  • mysql隐式转换

    1.string vs number 值类型和字符串类型比较时,mysql将字符串类型转换为值类型。尽量避免类型的...

  • JavaScript 类型转换

    仅供学习,转载请注明出处 1、直接转换 parseInt() 与 parseFloat() 2、隐式转换 “==”...

  • C++类型转换

    C++的类型转换分为隐式转换和显式转换 隐式转换举例: int i=4; double d=i;//隐式转换 显式...

  • scala-隐式机制及Akka

    隐式机制及Akka 隐式转换 隐式转换和隐式参数时Scala中两个非常强大的功能,利用隐式转换和隐式参数,可以提供...

  • MySQL的隐式转换

    MySQL在什么情况下会产生隐式转换 当查询条件左右两侧类型不匹配的时候会发生隐式转换,可能导致查询无法使用索引。...

网友评论

      本文标题:[转载]Mysql 隐式转换

      本文链接:https://www.haomeiwen.com/subject/mqoucxtx.html