查询具有字符串数据类型的 int 列对 mysql 查询有任何性能影响吗?

Does querying int column with string datatype have any performance impact in mysql queries?

假设我有一个 table 作为:

create table any_table (any_column_1 int, any_column_2 varchar(255));
create index any_table_any_column_1_IDX USING BTREE ON any_table (any_column_1);

(注意:此处索引类型无关紧要)

我想知道使用 intstring 查询 any_column 是否对性能有任何影响,即

select * from any_table where any_column_1 = 12345;

与这个在性能方面有什么不同吗?

select * from any_table where any_column_1 = '12345';

我在网上看了一圈,确实没有遇到过这种特殊情况。

对于索引整数列,无论哪种方式都可以。当您将整数列与常量进行比较时,无论您将其格式化为整数还是字符串,常量值都会转换为整数。

您可以使用 EXPLAIN 确认这一点。在这两种情况下,EXPLAIN 表明它将使用索引(type: ref 表示索引查找),并且性能将相同。

mysql> explain select * from any_table where any_column_1 = 12345;
+----+-------------+-----------+------------+------+----------------------------+----------------------------+---------+-------+------+----------+-------+
| id | select_type | table     | partitions | type | possible_keys              | key                        | key_len | ref   | rows | filtered | Extra |
+----+-------------+-----------+------------+------+----------------------------+----------------------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | any_table | NULL       | ref  | any_table_any_column_1_IDX | any_table_any_column_1_IDX | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+-----------+------------+------+----------------------------+----------------------------+---------+-------+------+----------+-------+

mysql> explain select * from any_table where any_column_1 = '12345';
+----+-------------+-----------+------------+------+----------------------------+----------------------------+---------+-------+------+----------+-------+
| id | select_type | table     | partitions | type | possible_keys              | key                        | key_len | ref   | rows | filtered | Extra |
+----+-------------+-----------+------------+------+----------------------------+----------------------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | any_table | NULL       | ref  | any_table_any_column_1_IDX | any_table_any_column_1_IDX | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+-----------+------------+------+----------------------------+----------------------------+---------+-------+------+----------+-------+

如果您在您的示例 any_column_2 中为字符串列编制了索引,那将会有所不同,因为字符串列的排序规则必须与您与之比较的值的排序规则相匹配。默认情况下,字符串文字将转换为兼容的排序规则,因此它使用索引:

create index any_table_any_column_2_IDX USING BTREE ON any_table (any_column_2);

mysql> explain select * from any_table where any_column_2 = '12345';
+----+-------------+-----------+------------+------+----------------------------+----------------------------+---------+-------+------+----------+-------+
| id | select_type | table     | partitions | type | possible_keys              | key                        | key_len | ref   | rows | filtered | Extra |
+----+-------------+-----------+------------+------+----------------------------+----------------------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | any_table | NULL       | ref  | any_table_any_column_2_IDX | any_table_any_column_2_IDX | 768     | const |    1 |   100.00 | NULL  |
+----+-------------+-----------+------------+------+----------------------------+----------------------------+---------+-------+------+----------+-------+

但是整数文字没有排序规则,所以你会收到警告,并且无法使用索引。 EXPLAIN 显示 type: ALL,因此它将执行 table-scan,如果您查询包含很多行的 table,那么性能会很差。

mysql> explain select * from any_table where any_column_2 = 12345;
+----+-------------+-----------+------------+------+----------------------------+------+---------+------+------+----------+-------------+
| id | select_type | table     | partitions | type | possible_keys              | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-----------+------------+------+----------------------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | any_table | NULL       | ALL  | any_table_any_column_2_IDX | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-----------+------------+------+----------------------------+------+---------+------+------+----------+-------------+
1 row in set, 3 warnings (0.00 sec)

mysql> show warnings;
+---------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                                                     |
+---------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 1739 | Cannot use ref access on index 'any_table_any_column_2_IDX' due to type or collation conversion on field 'any_column_2'                                                                                     |
| Warning | 1739 | Cannot use range access on index 'any_table_any_column_2_IDX' due to type or collation conversion on field 'any_column_2'                                                                                   |
| Note    | 1003 | /* select#1 */ select `test2`.`any_table`.`any_column_1` AS `any_column_1`,`test2`.`any_table`.`any_column_2` AS `any_column_2` from `test2`.`any_table` where (`test2`.`any_table`.`any_column_2` = 12345) |
+---------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+