pupuk / mysql

Questions & Thinking

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MySQL使用过程中的一些坑

pupuk opened this issue · comments

路漫漫其修远兮

Records

字段设计成字符串(如:char,varchar),查询是使用 数字,导致查询结果不准确或索引失效

如下,有一张表order订单表
mysql> desc order;

+-----------------------+------------------------+------+-----+---------+----------------+
| Field                 | Type                   | Null | Key | Default | Extra          |
+-----------------------+------------------------+------+-----+---------+----------------+
| order_id              | int(11)                | NO   | PRI | NULL    | auto_increment |
| order_sn              | varchar(20)            | NO   | MUL | NULL    |                |
+-----------------------+------------------------+------+-----+---------+----------------+

order_sn上有一索引。
使用SQL语句:
SELECT order_id, order_sn FROM my_order WHERE order_sn = '20180105160500862725';
如果order_sn的值是20180105160500862725,就会导致查询结果多了。

mysql> SELECT order_id, order_sn FROM `my_order` WHERE order_sn = '20180105160500862725';
+----------+----------------------+
| order_id | order_sn             |
+----------+----------------------+
|     3827 | 20180105160500862725 |
+----------+----------------------+
1 row in set

mysql> SELECT order_id, order_sn FROM `my_order` WHERE order_sn = 20180105160500862725;
+----------+----------------------+
| order_id | order_sn             |
+----------+----------------------+
|     3671 | 20180105160500861022 |
|     3553 | 20180105160500862149 |
|     3827 | 20180105160500862725 |
|     3786 | 20180105160500863824 |
|     3493 | 20180105160500864895 |
+----------+----------------------+
5 rows in set

查询结果不准确

当等号两边的值是不同类型时,MySQL会做隐式的类型转换。上面第二条MySQL语句,会做一个
F(String) = Number的操作,F是把String转成Number,然后与Number比较

mysql> SELECT '20180105160500861022' =  20180105160500862725 AS result;
+--------+
| result |
+--------+
|      1 |
+--------+

MySQL的隐式类型转换,网上资料很多,在此也不赘述,官方文档还是写的很详细的
https://dev.mysql.com/doc/refman/8.0/en/type-conversion.html

索引失效

也是同样的原因:

For comparisons of a string column with a number, MySQL cannot use an index on the column to look up the value quickly. If str_col is an indexed string column, the index cannot be used when performing the lookup in the following statement:
SELECT * FROM tbl_name WHERE str_col=1;
The reason for this is that there are many different strings that may convert to the value 1, such as '1', ' 1', or '1a'.

如果str_col是被索引的字符串列,当用数字number来查询比较时,不能用索引,是因为很多可能的字符串都能转换成相同的数值,MySQL显然不可能,列出这些可能的、有限的字符串。

要避免这个问题:
1、可以使用int的字段,尽量用int,不用char或者varchar,一是可以节省字节数,节省存储空间。二是也可以避免如上的错误,三是int类型的比较计算在微观上还是比char省资源。
2、应用程序框架,对所有字段的值都加上引号
如:SELECT * FROM orderWHEREcol = 'value';
不管col列是int,还是char,varchar类型
如果col列是int,MySQL在查询的时候,也会把value从string转成int。