4

可能重复:
在 Mysql 查询中引用整数的缺点?

我在 MYSql 数据库上有一个非常简单的名为 Device 的表。

+-----------------------------------+--------------+------+-----+----------------+
| Field                             | Type         | Null | Key | Extra          |
+-----------------------------------+--------------+------+-----+----------------+
| DTYPE                             | varchar(31)  | NO   |     |                |
| id                                | bigint(20)   | NO   | PRI | auto_increment |
| dateCreated                       | datetime     | NO   |     |                |
| dateModified                      | datetime     | NO   |     |                |
| phoneNumber                       | varchar(255) | YES  | MUL |                |
| version                           | bigint(20)   | NO   |     |                |
| oldPhoneNumber                    | varchar(255) | YES  |     |                |
+-----------------------------------+--------------+------+-----+----------------+

该表有超过 100K 的记录。我正在运行一个非常简单的查询

select * from AttDevice where phoneNumber = 5107357058;

此查询几乎需要 4-6 秒,但是当我稍微更改此查询时,如下所示。

select * from AttDevice where phoneNumber = '5107357058';

执行几乎不需要时间。请注意,phoneNumber 列是 varchar。我不明白为什么前一种情况需要更长的时间而后来不需要。这两个查询之间的区别在于单引号。如果是这样,MYSQL 是否会以不同的方式处理这些查询,那为什么?

编辑 1

我使用EXPLAIN并得到了以下输出,但不知道如何解释这两个结果。

mysql> EXPLAIN select * from AttDevice where phoneNumber = 5107357058;
+----+-------------+-----------+------+---------------------------------------+------+---------+------+---------+-------------+
| id | select_type | table     | type | possible_keys                         | key  | key_len | ref  | rows    | Extra       |
+----+-------------+-----------+------+---------------------------------------+------+---------+------+---------+-------------+
|  1 | SIMPLE      | Device    | ALL  | phoneNumber,idx_Device_phoneNumber | NULL | NULL    | NULL | 6482116 | Using where |
+----+-------------+-----------+------+---------------------------------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)

mysql> EXPLAIN select * from AttDevice where phoneNumber = '5107357058';
+----+-------------+-----------+------+---------------------------------------+-------------+---------+-------+------+-------------+
| id | select_type | table     | type | possible_keys                         | key         | key_len | ref   | rows | Extra       |
+----+-------------+-----------+------+---------------------------------------+-------------+---------+-------+------+-------------+
|  1 | SIMPLE      |   Device  | ref  | phoneNumber,idx_Device_phoneNumber    | phoneNumber | 258     | const |    2 | Using where |
+----+-------------+-----------+------+---------------------------------------+-------------+---------+-------+------+-------------+
1 row in set (0.00 sec)

有人可以解释一下 EXPLAIN 查询输出中存在的键、key_len 和行吗?

4

5 回答 5

3

1)感谢您的“解释”。我们所有人(包括你,我敢肯定)都知道问题在于 mysql 必须将整数转换为字符串,并且必须为每一行执行此操作。但是您的“解释”证明了这一点。

2)这是一篇关于解释的简短文章:

*possible_keys* 显示哪些索引适用于该查询, 告诉我们实际使用了哪些索引-... 最后,条目告诉我们 MySQL 必须查看多少行才能找到结果集。

Search value:   key:        type:  ref:   rows:  
-------------   ---         ----   ----   ----
5107357058      NULL        ALL    NULL   6482116
'5107357058'    phoneNumber ref    const  2

3)“ref”列是“与索引比较的列”。在第二种情况下,字符串文字(“常量”)“5107357058”与键“phoneNumber”进行了比较。在第一种情况下,没有可用的密钥(因为您的搜索条件是完全不同的类型);因此“ref”为NULL。

4)“类型”列是“连接类型”。“Ref”表示“从该表中读取所有具有匹配索引值的行”(在本例中为 2 行)。“ALL”表示“全表扫描”。在这种情况下,这意味着 600 万行。

5)这是“解释”的mysql文档:

于 2012-10-04T05:12:28.713 回答
2

您通过不引用电话号码来欺骗 MySQL 做出错误的选择。考虑:

  1. 列定义为 varchar
  2. 在第一种(未加引号的)情况下,您将值提供为整数(长整数)。我原以为 MySQL 可以解决这个问题,但显然它没有,并进行了全表扫描。
  3. 在第二种(引用的)案例中,您提供了正确数据类型(字符)的搜索键,MySQL 选择了索引而不是全表扫描。
于 2012-10-04T01:52:57.987 回答
2

当您使用数字作为操作数时,不能使用 varchar 索引,摘自关于隐式类型转换的精细文档:

对于字符串列与数字的比较,MySQL 不能使用列上的索引来快速查找值。如果 str_col 是索引字符串列,则在以下语句中执行查找时不能使用索引:

SELECT * FROM tbl_name WHERE str_col=1;

原因是有许多不同的字符串可以转换为值 1,例如 '1'、'1' 或 '1a'。

于 2012-10-04T01:53:24.180 回答
1

我相信 MySQL 在第一个示例中必须将数字转换为 varchar。在第二个例子中它没有。我猜这就是差异的来源。

于 2012-10-03T23:44:12.527 回答
1

第一个示例逐个查看表,另一个使用索引。

http://dev.mysql.com/doc/refman/5.0/en/show-columns.html
如果 Key 是 MUL,则允许在列中多次出现给定值。该列是可以包含 NULL 值的非唯一索引或唯一值索引的第一列。

因此,第二个查询不是扫描所有空值,而是专门寻找非空值,从而加快处理速度。

....我认为。

于 2012-10-04T01:07:20.320 回答