Mysql implicit type conversion may not use index?
Have you ever discovered during the actual development and operation and maintenance process that when executing a query on a table with a large amount of data, the where
fields behind the conditions are obviously indexed, but the query takes a long time. Why is this?
Let’s talk about the conclusion first: If MySQL varchar
implicit type conversion occurs in the index of type field, the index will be invalid.
Create a user table with two attributes and and a name
primary key field:age
id
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `user_name` (`name`),
KEY `user_age` (`age`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
name
We have created indexes for the fields " and " respectively age
. Let's test and verify these two indexes.
Let's try using age
the field to perform a normal type of query and see what the execution plan looks like:
mysql> explain select * from user where age = 1;
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| 1 | SIMPLE | user | NULL | ref | user_age | user_age | 5 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
We can see that the column of the execution plan type
is displayed as ref
and possible_keys
the column user_age
indicates that the index may be used, while key
the value of the column user_age
indicates that user_age
the index will eventually be decided to be used.
age
The field itself is a numeric type, so will queries that perform implicit type conversion of numeric types use indexes? We continue testing and change where
the numbers in the condition 1
to strings '1'
:
mysql> explain select * from user where age = '1';
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| 1 | SIMPLE | user | NULL | ref | user_age | user_age | 5 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
We see that the execution plan of Mysql is exactly the same and user_age
this index will still be used. Therefore, when Mysql treats implicit type conversion of int type fields, it will not cause index failure. So, will implicit type conversion of varcher type fields cause index failure? Let's continue testing.
First verify that using normal types will lead to indexing:
mysql> explain select * from user where name = '1';
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
| 1 | SIMPLE | user | NULL | ref | user_name | user_name | 768 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
varcher
You can see the type field used after the where condition name
, and =
the subsequent data type uses the name
same type as the field definition . The field varcher
in the above result indicates that the index is removed. Okay, let's change the string type to a numeric type and see the effect:key
user_name
'1'
1
mysql> explain select * from user where name = 1;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | user | NULL | ALL | user_name | NULL | NULL | NULL | 1 | 100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 3 warnings (0.00 sec)
Hey, we found that type
the field has changed NULL
, possible_keys
the value of the field is still the same user_name
, but key
the value of the field has changed NULL
, indicating that Mysql still wants to use the index, but ultimately decided not to use the index.
Why is this so?
When Mysql compares values with inconsistent types, it will do its best to perform the comparison. In the above case, the field name
is varchar
of type, but the where name = 1;
in the statement 1
is of numeric type. At this time, Mysql name
converts the field value into a floating point number for comparison, but in the index All stored are strings, so each record value needs to be converted, which requires a full table scan.