[英]How Mysql treats comparing a no string value to a indexed varchar column?
最近我在以下用例中发现了一个性能问题之前我有一个带有INT索引列“MyCode”的表“MyTable”之后需要更改将“MyCode”列转换为VARCHAR的表结构(保留了列上的索引)
ALTER TABLE MyTable CHANGE MyCode MyCode VARCHAR(250) DEFAULT NULL
然后经历了意外的延迟,正在执行的查询如下:
SELECT * FROM MyTable where MyCode = 1234
这个查询完全忽略了MyCode VARCHAR索引,印象是它是全扫描表
将查询转换为
SELECT * FROM MyTable where MyCode = "1234"
性能回归到VARCHAR索引的最佳利用
所以问题是......如何解释它......以及MySQL如何处理索引。 或者可能需要更改某些数据库设置以避免这种情况?
int_col = 1234 -- no problem; same type
char_col = "1234" -- no problem; same type
int_col = "1234" -- string is converted to number, then no problem
char_col = 1234 -- converting all the strings to numbers -- tedious
在第四种情况下,索引是无用的,因此优化器会查找其他一些方法来执行查询。 这很可能导致“全表扫描”。
主要的例外是“覆盖索引”,它只是稍微快一点 - 涉及“全索引扫描”。
我接受了Rick James的回答,因为他明白了。
但是我想在进行一些测试后添加更多信息。
问题中的情况是:当过滤列为varchar类型且提供的filter by值不是字符串时,MySQL实际上如何比较两个值。 如果是这种情况,您将失去利用应用于VARCHAR列的索引的机会,在您的查询中性能会大幅下降,而应该是立即和简单的。
解释是,在与VARCHAR具有不同类型的给定值前面的MySQL将执行全表扫描,并且对于每个记录的字段将执行CAST(varcharcol as providedvaluetype)并将结果与提供的值进行比较。
例如
有一个名为“code”的VARCHAR列并进行过滤
SELECT * FROM table WHERE code=1234
将完全扫描每条记录,就像这样做
SELECT * FROM table WHERE CAST(code as UNSIGNED)=1234
请注意,如果您将对照0进行测试
SELECT * FROM table WHERE CAST(code as UNSIGNED)=0
你将收到所有记录,其中包含一个字符串,其CAST到UNSIGNED将不具有mysql CAST函数的无符号含义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.