sql int转换为varchar_常见SQL优化实践

(1)负向条件查询不能使用索引select * from user where status!=0 ,not in/not exists都不是好习惯可以优化为in查询:select * from user where status in(1,2)

数据准备:

CREATE TABLE `user` ( `id` bigint(20) NOT NULL, `name` varchar(32) DEFAULT NULL, `age` int(11) DEFAULT NULL, `status` int(1) DEFAULT NULL, KEY `index_status` (`status`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;INSERT INTO `user` VALUES ('1', '张三', '12', '0');INSERT INTO `user` VALUES ('2', '李四', '23', '1');INSERT INTO `user` VALUES ('3', '王五', '34', '2');//在status字段添加索引

测试结果:

e53e375dd7c6845fbe64fc3c9a881ac2.png

type连接类型为:all(全表扫描)

4bd499eb69250cb67d5a673f43f02671.png

type连接类型为:ref(非注解唯一索引扫描)

(2)前导模糊查询不能使用索引select * from user where name like '%张三' 而非前导模糊查询则可以:select * from user where name like '张三%'

数据准备:

CREATE TABLE `user` ( `id` bigint(20) NOT NULL, `name` varchar(32) DEFAULT NULL, `age` int(11) DEFAULT NULL, `status` int(1) DEFAULT NULL, KEY `index_name` (`name`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;INSERT INTO `user` VALUES ('1', '张三', '12', '0');INSERT INTO `user` VALUES ('2', '李四', '23', '1');INSERT INTO `user` VALUES ('3', '王五', '34', '2');//在name字段添加索引

测试结果:

178e142c5650128bea8505452200f9e2.png

type连接类型为:all(全表扫描)

231a4ae3fa915e040ad3158dc51a3e9a.png

type连接类型为:range(范围扫描)

(3)数据区分度不大的字段不宜使用索引select * from user where sex=1原因:性别只有男,女,每次过滤掉的数据很少,不宜使用索引。经验上能过滤80%数据时可以使用索引

(4)在属性上进行计算不能命中索引select * from user where YEAR(birth_date) < = '2017' 即使date上建立了索引,也会全表扫描,可优化为值计算:select * from user where birth_date< = '2000-01-01'

数据准备

CREATE TABLE `user` ( `id` bigint(20) NOT NULL, `name` varchar(32) DEFAULT NULL, `sex` int(1) DEFAULT NULL, `birth_date` date DEFAULT NULL, KEY `index_birth_date` (`birth_date`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;INSERT INTO `user` VALUES ('1', '张三', '0', '2010-02-03');INSERT INTO `user` VALUES ('2', '李四', '1', '2000-02-02');INSERT INTO `user` VALUES ('3', '王五', '1', '1998-09-09');//在birth_date上添加索引

测试结果:

7aa9027ea9709a715ffbebe5f6ef0625.png

全表扫描,没有列出可能应用的索引

2552d4ca93c1ef7b9c796e268d82d83c.png

全表扫描,显示可能应用在这张表中的索引

(5)如果业务大部分是单条查询,使用Hash索引性能更好,例如用户表select * from user where id=1或select * from user where name='张三',原因:B-Tree索引的时间复杂度是O(log(n))Hash索引的时间复杂度是O(1)

(6)允许为null的列,查询有潜在大坑,单列索引不存null值,复合索引不存全为null的值,如果列允许为null,可能会得到"不符合预期”结果,所以请使用not null约束以及默认值

(7)复合索引最左前缀,并不是值SQL语句的where顺序要和复合索引一致,用户表建立了(login_name, passwd)的复合索引,select * from user where login_name=? and passwd=? ; select * from user where passwd=? and login_name=?; select * from user where login_name=? 都能命中索引,他们都满足复合索引最左前缀。 然而select * from user where passwd=?不能命中索引,不满足复合索引最左前缀

数据准备

CREATE TABLE `user` ( `id` bigint(20) NOT NULL, `login_name` varchar(32) DEFAULT NULL, `password` varchar(32) DEFAULT NULL, KEY `index_loginname_password` (`login_name`,`password`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;//在login_name,password列建立复合索引,KEY `index_loginname_password` (`login_name`,`password`)

测试结果:

d3c551e0c4f93934f51a6f68a52f66d8.png

三条sql语句都能命中索引

47788594521f8bdaa6a9b1b2641ad2f6.png

不满足复合索引最左原则,不能命中索引

(8)如果明确知道只有一条结果返回,limit 1能够提高效率select * from user where login_name=? 可以优化为:select * from user where login_name=? limit 1原因:你知道只有一条结果,但数据库并不知道,明确告诉它,让它主动停止游标移动

(9)强制类型转换会全表扫描select * from user where phone_no=13800001234你以为会命中phone_no索引么?那就错了,因为phone_no是varchar(11) ,所以13800001234会强制转换类型,如果phone_no为bigint(20),那么phone_no=13800001234和phone_no='13800001234'都会走索引

数据准备

CREATE TABLE `user` ( `id` bigint(20) NOT NULL, `phone_no` varchar(11) DEFAULT NULL, KEY `index_phone_no` (`phone_no`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;//在phone_no列加索引,KEY `index_phone_no` (`phone_no`)

测试结果:

be0a471388e99d4301cd79df729bb52a.png

发生类型转换,没有走索引

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值