我可以在不中断INDEX的情况下将VARCHAR转换为INT吗?

时间:2020-01-13 14:31:06

标签: mysql performance indexing casting

需要搜索表foo

foo 结构为

id |东西

字段INDEX中有一个something

我要搜索“ INT之间”:

SELECT CAST(something as INT) as something_int FROM foo foo_1
WHERE something_int > 1 AND something_int < 9999

在这种情况下,索引将被使用还是损坏?

2 个答案:

答案 0 :(得分:1)

WHERE some_varchar BETWEEN '1' AND '2000'  -- fast but probably incorrect
WHERE some_varchar BETWEEN 1 AND 2000      -- slow but correct
WHERE some_int BETWEEN '1' AND '2000'      -- fast
WHERE some_int BETWEEN 1 AND 2000          -- fast (same as previous)

发生了什么事?

  • 将文本与数字进行比较时,文本侧将转换为数字,然后执行数字比较。
  • 文本到文本比较会进行字符串比较;数字与数字进行数字比较。
  • 上面,我说“慢”是指不能使用索引。如果可以使用索引,则为“快速”。
  • “不正确”的问题与在VARCHAR中对一组数字进行排序,然后想知道列表为何乱序的问题相同:1,10,11,...,19,2, 20,...,29,3,...
  • CAST()只是我在这里谈论的隐式转换的显式版本。
  • CAST('2000' TO INT)是在“编译时”完成的,因此优化程序将其视为简单的2000(数字,无函数调用)。
  • 另一方面,在上面的第二个示例中,
  • some_varchar >= 1变成了CAST(some_varchar TO INT) >= 1
  • 根据经验,“在函数调用中隐藏列可防止使用索引。请参阅Wikipedia中的”可精简”。

答案 1 :(得分:0)

否,将不使用索引。

CREATE TABLE foo(something varchar(20) primary key) engine=myisam;
INSERT INTO foo VALUES ('1|abc'), ('3456|def');

DESCRIBE SELECT * FROM foo WHERE CAST(something as INT) BETWEEN 1 AND 2000;
+------+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                    |
+------+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
|    1 | SIMPLE      | tt    | index | NULL          | PRIMARY | 82      | NULL |    2 | Using where; Using index |
+------+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+

DESCRIBE SELECT * FROM foo WHERE something BETWEEN '1' AND '2000';
+------+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                    |
+------+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
|    1 | SIMPLE      | tt    | range | PRIMARY       | PRIMARY | 82      | NULL |    1 | Using where; Using index |
+------+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+

请注意,第一个查询的possible_keysNULL(而发现的rows2)。

注意:即使查询的字符集与索引的字符集不匹配,也会发生这种情况。

创建一个单独的INT索引(例如,使用function index语法)。