我在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是否会对这些问题进行不同的查询,如果是,为什么呢?
我使用了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和行吗?
答案 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做出了错误的选择。考虑:
答案 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值的唯一值索引。
因此,第二个查询不是扫描所有空值,而是专门查找非空值,从而加快速度。
....我想。