将整数分配给where子句上的varchar列时的巨大性能差异

时间:2015-07-23 01:23:56

标签: mysql

我有一个表说表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列时发生了什么。

2 个答案:

答案 0 :(得分:1)

正如Type Conversion in Expression Evaluation中所述,当您比较VARCHARINT时,通过将两者都转换为浮点数来完成比较。任何子弹都没有特别提到这种组合,所以最后一个适用:

  
      
  • 在所有其他情况下,将参数作为浮点(实数)进行比较。
  •   

因此,比较不能使用列的索引,因为索引只包含原始字符串,而不是其值作为数字。因此,它必须遍历表格的每一行,将字符串转换为数字,并将其与12345进行比较。

答案 1 :(得分:1)

显然,区别在于使用索引。使用索引时,查找非常非常快。如果没有索引,查询需要进行全表扫描。

问题是此查询不使用索引的原因:

select * from A where column_x = 12345

类型转换规则在documentation中说明。但是,关键在于:

  
      
  • 在所有其他情况下,将参数作为浮点(实数)进行比较。
  •   

这说明被转换为数字,而不是转换为字符串的常量。因此,您的查询等同于:

where cast(column_x as float) = cast(12345 as float)

当在列上使用函数时,MySQL无法再利用索引。如果没有索引,查询必须执行全表扫描。

故事的道德:比较值时,尽量确保类型相同。