我有一个表说表A,它有一个varchar(120)列,比如column_x。该表有大约400万条记录。表A在列column_x上创建了一个索引。当我执行select
查询时,我意外地将一个integer
分配给column_x。查询如下所示:
select * from A where column_x = 12345
此查询在大约20秒后完成。当我像这样重写查询时:
select * from A where column_x = '12345'
查询立即完成。然后我使用explain
语句,结果如下:
id: 1
select_type: SIMPLE
table: mt_tm_day
type: ALL
possible_keys: idx_mt_tm_day_ps_id
key: NULL
key_len: NULL
ref: NULL
rows: 4129271
Extra: Using where
1 row in set (0.00 sec)
id: 1
select_type: SIMPLE
table: A
type: ref
possible_keys: index_on_column_x
key: index_on_column_x
key_len: 363
ref: const
rows: 116
Extra: Using index condition
1 row in set (0.00 sec)
所以我的问题是将一个整数分配给where子句的varchar列时发生了什么。
答案 0 :(得分:1)
正如Type Conversion in Expression Evaluation中所述,当您比较VARCHAR
和INT
时,通过将两者都转换为浮点数来完成比较。任何子弹都没有特别提到这种组合,所以最后一个适用:
- 在所有其他情况下,将参数作为浮点(实数)进行比较。
因此,比较不能使用列的索引,因为索引只包含原始字符串,而不是其值作为数字。因此,它必须遍历表格的每一行,将字符串转换为数字,并将其与12345
进行比较。
答案 1 :(得分:1)
显然,区别在于使用索引。使用索引时,查找非常非常快。如果没有索引,查询需要进行全表扫描。
问题是此查询不使用索引的原因:
select * from A where column_x = 12345
类型转换规则在documentation中说明。但是,关键在于:
- 在所有其他情况下,将参数作为浮点(实数)进行比较。
这说明列被转换为数字,而不是转换为字符串的常量。因此,您的查询等同于:
where cast(column_x as float) = cast(12345 as float)
当在列上使用函数时,MySQL无法再利用索引。如果没有索引,查询必须执行全表扫描。
故事的道德:比较值时,尽量确保类型相同。