我有一个带有这样架构的测试表:
CREATE TABLE `indextest` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
Run Code Online (Sandbox Code Playgroud)
这是表中的行:
mysql [localhost] {msandbox} (test) > select * from indextest;
+----+--------+
| id | name |
+----+--------+
| 3 | 111222 |
| 1 | hello |
| 2 | world |
| 4 | wow |
+----+--------+
4 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
当我针对name
带有字符串的列查询表时,它看起来不错:
mysql [localhost] {msandbox} (test) > explain select * from indextest where name='111222'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: indextest
type: ref
possible_keys: idx_name
key: idx_name
key_len: 13
ref: const
rows: 1
Extra: Using where; Using index
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
但是如果我使用数字作为查询参数,explain 显示查询优化器正在执行索引扫描:
mysql [localhost] {msandbox} (test) > explain select * from indextest where name=111222\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: indextest
type: index
possible_keys: idx_name
key: idx_name
key_len: 13
ref: NULL
rows: 4
Extra: Using where; Using index
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
在其他一些情况下(在在线慢查询中发现),查询优化器甚至建议使用表扫描进行类似的查询。
我不明白为什么它的行为是这样的,但不仅仅是引发错误或自动将数字转换为字符串。
小智 4
我认为这是因为数字可以在文本中以多种方式表示。根据MySQL 如何使用索引的文档:
如果在不进行转换的情况下无法直接比较值,则不同列的比较可能会阻止使用索引。假设将数字列与字符串列进行比较。对于数字列中的给定值(例如 1),它可能与字符串列中的任意数量的值(例如“1”、“1”、“00001”或“01.e1”(原文如此))进行比较。这排除了对字符串列使用任何索引。
(我认为01.e1
这是一个拼写错误,应该阅读0.1e1
。)
由于数字并不等于一个且仅一个文本值,因此无法使用索引。
另一方面,同样的情况并不适用于相反的方向。数字的文本表示确实等于一个且仅一个数值。换句话说:
虽然 numeric1
可以等同于文本'1'
, ' 1'
, '00001'
, 或'0.1e1'
,但
文本'1'
, ' 1'
, '00001'
, and '0.1e1'
all 仅等同于 numeric 1
。
因此,如果您有一个数字列并将字符串值与其进行比较,则可以按您的预期使用索引。(真的,我刚刚尝试过。)