简单的SQL语句需要更长的时间来执行

时间:2012-10-03 23:31:47

标签: mysql sql

  

可能重复:
  Disadvantages of quoting integers in a Mysql query?

我在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,key_len和行吗?

5 个答案:

答案 0 :(得分:3)

1)谢谢你的“EXPLAIN”。我们所有人(包括你,我确定)知道问题是mysql必须将整数转换为字符串,并且必须为每一行执行此操作。但是你的“EXPLAIN”证明了它。

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

        

* possible_keys *显示哪些索引适用于此查询以及   告诉我们实际使用了哪些-...最后条目告诉我们   我们需要查看多少行来查找结果集。

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)这是“EXPLAIN”的mysql文档:

答案 1 :(得分:2)

你没有引用电话号码,误以为MySQL做出了错误的选择。考虑:

  1. 列定义为varchar
  2. 在第一个(未引用的)情况下,您将值提供为整数(long)。我原本以为MySQL可以解决这个问题,但显然没有,并且进行了全表扫描。
  3. 在第二个(引用)的情况下,您使用正确的数据类型(字符)给出了搜索键,MySQL选择了全表扫描的索引。

答案 2 :(得分:2)

当您使用数字作为操作数时,不能使用varchar索引,摘自implicit type conversions上的精细文档:

  

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

     

SELECT * FROM tbl_name WHERE str_col = 1;

     

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

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

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

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

....我想。