首页 运维知识 关于MySQL SQL优化之字符串索引隐式转换

关于MySQL SQL优化之字符串索引隐式转换

SQL语句非常简单,就是select * from test_1 where user_id=1 这种类型,而且user_id上已经建立索引了,怎么还是查询很慢? test_1的表…

SQL语句非常简单,就是select * from test_1 where user_id=1 这种类型,而且user_id上已经建立索引了,怎么还是查询很慢?

test_1的表结构:

CREATE TABLE `test_1` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`user_id` varchar(30) NOT NULL,

`name` varchar(30) DEFAULT NULL,

PRIMARY KEY (`id`),

KEY `idx_user_id` (`user_id`)

) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

查看执行计划,可以看出进行了全表扫描,并没有用上user_id的索引。

mysql> explain select * from test_1 where user_id=1;

+—-+————-+——–+——+—————+——+———+——+——+————-+

| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows | Extra       |

+—-+————-+——–+——+—————+——+———+——+——+————-+

|  1 | SIMPLE      | test_1 | ALL  | idx_user_id   | NULL | NULL    | NULL |    3 | Using where |

+—-+————-+——–+——+—————+——+———+——+——+————-+

1 row in set (0.01 sec)

仔细看下表结构,user_id的字段类型:  `user_id` varchar(30) NOT NULL,

而用户传入的是int,这里会有一个隐式转换的问题。隐式转换会导致全表扫描。

 

把输入改成字符串类型,执行计划如下,这样就会很快了。

mysql> explain select * from test_1 where user_id=’1′;

+—-+————-+——–+——+—————+————-+———+——-+——+————-+

| id | select_type | table  | type | possible_keys | key         | key_len | ref   | rows | Extra       |

+—-+————-+——–+——+—————+————-+———+——-+——+————-+

|  1 | SIMPLE      | test_1 | ref  | idx_user_id   | idx_user_id | 92      | const |    1 | Using where |

+—-+————-+——–+——+—————+————-+———+——-+——+————-+

1 row in set (0.00 sec)

此外,还需要注意的是:

数字类型的0001等价于1

字符串的0001和1不等价

 

mysql> select * from test_1;

+—-+———+——+

| id | user_id | name |

+—-+———+——+

|  1 | 0001    | kate |

|  2 | 1101    | Jim  |

|  3 | 1       | Jim  |

+—-+———+——+

3 rows in set (0.01 sec)

mysql> select * from test_1 where user_id=1;

+—-+———+——+

| id | user_id | name |

+—-+———+——+

|  1 | 0001    | kate |

|  3 | 1       | Jim  |

+—-+———+——+

2 rows in set (0.00 sec)

mysql> select * from test_1 where user_id=’1′;

+—-+———+——+

| id | user_id | name |

+—-+———+——+

|  3 | 1       | Jim  |

+—-+———+——+

1 row in set (0.00 sec)

如果表定义的是int字段,传入的是字符串,则不会发生隐式转换。

看下面的测试:

CREATE TABLE `test_2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`name` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

mysql> explain select * from test_2 where user_id=1;
+—-+————-+——–+——+—————+————-+———+——-+——+——-+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+—-+————-+——–+——+—————+————-+———+——-+——+——-+
| 1 | SIMPLE | test_2 | ref | idx_user_id | idx_user_id | 4 | const | 2 | |
+—-+————-+——–+——+—————+————-+———+——-+——+——-+
1 row in set (0.00 sec)

mysql> explain select * from test_2 where user_id=’1′;
+—-+————-+——–+——+—————+————-+———+——-+——+——-+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+—-+————-+——–+——+—————+————-+———+——-+——+——-+
| 1 | SIMPLE | test_2 | ref | idx_user_id | idx_user_id | 4 | const | 2 | |
+—-+————-+——–+——+—————+————-+———+——-+——+——-+
1 row in set (0.00 sec)

免责声明:文章内容不代表本站立场,本站不对其内容的真实性、完整性、准确性给予任何担保、暗示和承诺,仅供读者参考,文章版权归原作者所有。如本文内容影响到您的合法权益(内容、图片等),请及时联系本站,我们会及时删除处理。

作者: 小小编

为您推荐

dell R710 更换raid卡后,raid卡信息没有了,处理方案

dell R710 更换raid卡后,raid卡信息没有了,处理方案

1.将一台服务器(A)的硬盘依次拔出,按相同顺序插入另一台同样配置的服务器(B) 2.启动服务器(B) 3.按提示键盘按...
PL SQL Developer 13连接Oracle数据库并导出数据详细操作教程方法

PL SQL Developer 13连接Oracle数据库并导出数据详细操作教程方法

下载 并安装 PL SQL Developer 13,默认支持中文语言 ========================...
关于一条sql语句在mysql中是如何执行的

关于一条sql语句在mysql中是如何执行的

最近开始在学习mysql相关知识,自己根据学到的知识点,根据自己的理解整理分享出来,本篇文章会分析下一个sql语句在my...
关于sql注入姿势总结(mysql)

关于sql注入姿势总结(mysql)

前言 学习了sql注入很长时间,但是仍然没有系统的了解过,这次总结一波,用作学习的资料。 从注入方法分:基于报错、基于布...
关于Oracle SQL外连接

关于Oracle SQL外连接

SQL提供了多种类型的连接方式,它们之间的区别在于:从相互交叠的不同数据集合中选择用于连接的行时所采用的方法不同。 连接...

发表回复

返回顶部