SQL 优化方法详解(2)

案例1:隐式转换

1、创建普通索引B+树

sql 复制代码
CREATE TABLE `user_test` (
  `id` int NOT NULL AUTO_INCREMENT,
  `userId` varchar(32) NOT NULL,
  `age` varchar(16) NOT NULL,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_userid` (`userId`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3

2、创建唯一索引,B+树

sql 复制代码
CREATE TABLE `device_shift_info` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  `workshop_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '车间编码',
  `workshop_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '车间名称',
  `line_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '线别编码',
  `line_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '线别名称',
  `device_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '设备编码',
  `device_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '设备名称',
  `shift_code` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '班次编码',
  `shift_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '班次名称',
  `shift_date` date DEFAULT NULL COMMENT '班次日期', 
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `device_shift_date` (`workshop_code`,`line_code`,`device_code`,`shift_date`,`shift_name`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='设备班次数据信息'

userId字段为字串类型,是B+树的普通索引,如果查询条件传了一个数字过去,会导致索引失效。如下:

sql 复制代码
explain select * from user_test WHERE userId =123

如果给数字加上'',也就是说,传的是一个字符串呢,当然是走索引,如下图:

sql 复制代码
explain select * from user_test WHERE userId ='123'

为什么第一条语句未加单引号就不走索引了呢?这是因为不加单引号时,是字符串跟数字的比较,它们类型不匹配,MySQL会做隐式的类型转换,把它们转换为浮点数再做比较。隐式的类型转换,索引会失效

案例2:最左匹配

联合索引

sql 复制代码
CREATE TABLE `user_test` (
  `id` int NOT NULL AUTO_INCREMENT,
  `user_id` varchar(32) NOT NULL,
  `age` varchar(16) NOT NULL,
  `name` varchar(255) NOT NULL,
  `remark` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_userid_name_age` (`user_id`,`name`,`age`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3
sql 复制代码
explain select * from user_test WHERE  1=1 and  user_id ='1'  and age  ='123' and   name ='1' -- 索引ref
explain select * from user_test WHERE  1=1   and age  ='123' and   name ='1' and  user_id ='1' -- 索引ref
explain select * from user_test WHERE  1=1 and  user_id ='1' and age  ='123' -- 索引ref
explain select * from user_test WHERE  1=1 and   name ='1' and age  ='123'  -- 索引index
explain select * from user_test WHERE   age  ='123'    -- 索引index
explain select * from user_test WHERE   remark  ='123'    -- 索引失效

案例3:深分页问题

当数量特别大的时候分页取数据

sql 复制代码
explain select id,name,balance from account where create_time> '2020-09-19' limit 100000,10;

limit语句会先扫描offset+n行,然后再丢弃掉前offset行,返回后n行数据。也就是说limit 100000,10,就会扫描100010行,而limit 0,10,只扫描10行。

limit 100000,10 扫描更多的行数,也意味着回表更多的次数

如何优化深分页问题? 一般采用标签记录法和延迟关联法
标签记录法:记录上次扫描的id(必须有自增的字段)

sql 复制代码
select  id,name,balance FROM account where id > 100000 limit 10;

延迟关联法

就是把条件转移到主键索引树

sql 复制代码
select  acct1.id,acct1.name,acct1.balance 
FROM account acct1 INNER JOIN (SELECT a.id FROM account a WHERE a.create_time > '2020-09-19' limit 100000, 10) AS acct2 on acct1.id= acct2.id;

优化思路就是,先通过idx_create_time二级索引树查询到满足条件的主键ID,再与原表通过主键ID内连接,这样后面直接走了主键索引了,同时也减少了回表

案例4:in元素过多

sql 复制代码
select * from user where user_id in (select author_id from artilce where type = 1);
当in 后面是一个子查询时候不确定有多少,般建议不要超过200个,如果超过了,建议分组,每次200一组进行
相关推荐
忘记92619 分钟前
mysql一条sql语句是如何运行的
数据库·mysql
emma_dd20 分钟前
final关键字
java
SimonKing22 分钟前
J人程序员的用屏技巧:软硬结合,让编码效率起飞
java·后端·程序员
小北方城市网23 分钟前
第 4 课:微服务 API 网关设计与接口全生命周期管理|统一入口与接口治理实战
java·大数据·运维·人工智能·python·深度学习·数据库架构
白典典25 分钟前
iTextPDF生成手册时目录页码与实际页码不匹配问题求助
java·spring·pdf·intellij-idea
进击的小菜鸡dd26 分钟前
Java求职面试:从Spring框架到微服务,谢飞机的奇妙面试之旅
java· 面试· 微服务· 数据库· 安全· spring· 缓存
计算机学姐33 分钟前
基于SpringBoot的高校体育场馆预约系统【个性化推荐算法+数据可视化统计】
java·vue.js·spring boot·后端·mysql·信息可视化·推荐算法
Coder_Boy_36 分钟前
基于SpringAI的在线考试系统设计-用户管理模块设计
java·大数据·人工智能·spring boot·spring cloud
Tan_Ying_Y37 分钟前
为什么InnoDB存储引擎默认使用B+树作为索引结构?B+树索引工作原理?
数据库·b树·oracle
lalala_lulu37 分钟前
MySQL数据库存储引擎的数据结构(超详细版)
数据结构·数据库·mysql