mysql索引优化实战<二>

1.好长时间没怎么写博客了 最近看了谷粒商城和k8s 感觉收获不小

在这里插入图片描述

CREATE TABLE `employees` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(24) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '姓名',
  `age` int NOT NULL DEFAULT '0' COMMENT '年龄',
  `position` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '职位',
  `hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '入职时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=27486 DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='员工表';

在这里插入图片描述

 还是这个表 ,表中有24785个数据,很多时候我们分页的时候会用
 select  * from employees  limit 1000,10 他这个sql 不光是只查询1001-1010这10条记录
他会查1-1010查出来 然后吧前面的1000条记录删掉  最终留下来10条记录
这样的话 越往后越慢
 因为越往后翻页 看起来页面上只展示10条记录 实际上他查找的数是非常多的
 这肯定是有问题的 你翻页翻到数据量大的时候 翻到后面页数 ,系统肯定会很慢
 呢么我们此时如何做优化  
 

在这里插入图片描述
在这里插入图片描述

 表中数据如果是自增的并且根据主键排序的
 这个表的数据根据主键Id 自增且连续,我们可以先计算出他这一页的初始值
然后再做limit 
比如说 
select * from employee where id >1000 limit 10 

在这里插入图片描述

我要查找某一页 我先查出来这一页的第一条数据 这样就是用了索引,这种方式我不用吧前面的1000条记录我都给查出来  而是直接在索引树里面定位到id>1000  从1000之后再去取10条
这样 

但是这是有条件的 自增且连续 

在这里插入图片描述
在这里插入图片描述

 根据非主键字段排序进行分页查询
但是我们工作中碰到的更多的是 你的数据不一定连续 而且不一定按照主键排序
select * from  employees order by name limit 1000, 5 

在这里插入图片描述

发现此时name字段没有用到索引,因为此时你的查询条件是联合索引的第一个元素,查询的结果集太多 mysql * 又要回表  所以直接走的全表 
对于这种场景我们怎么优化
explain seelct  * from employees order by name limit 1000 5 我们之前都用不到索引 [/用的文件排序]
explain select * from employees  e inner join (select id from employees order by name limit 1000,5) ed on e.id=ed.id
我们可以先查这个表 吧id 给挑选出来 这样只在这个二级索引树上就可以操作  就不用回表操作 再和我们的employees表做关联,因为此时是id关联 只要关联5条就完事了
此时order by 也是在索引树上排序  没有用到文件排序
e 这个表走的eq——ref 用的主键关联 效率很高
5个id我 全表扫描没关系啊
原来sql采用的文件排序 现在sql采用索引排序 
对分页的优化 先用索引吧id 过滤出来 然后再做关联

在这里插入图片描述

#== join 关联表的优化
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_a` (`a`)
) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8;

create table t2 like t1;
我们再往t1表中添加1w 条数据
delimiter ;;
# 创建存储过程
create procedure insert_t1()
begin
    declare i int;
    set i=1;
    while(i<=10000) do
        insert into t1(a,b) values(i,i);
        set i=i+1;
    end while;
end;;
delimiter ;

call insert_t1();
------------------------------>
给t2 加入100条数据
delimiter ;;
# 创建存储过程
create procedure insert_t2()
begin
    declare i int;
    set i=1;
    while(i<=100) do
        insert into t2(a,b) values(i,i);
        set i=i+1;
    end while;
end;;
delimiter ;

call insert_t2();
mysql的表关联常见有两种算法
(1)Nested-Loop Join 算法 [NLJ]
(2)Block Nested-Loop Join 算法[BNL]

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

EXPLAIN select * from t1 inner join t2 on t1.a= t2.a;
当我们使用inner join的时候  先执行t2表一行一行 拿记录
拿到一行的话去t1表里面做关联  
t2是100条记录 全表扫描 经过100次的扫描  t2拿一条记录 就会去t1表中
过滤一次 按照t1.a=t2.a这个条件过滤 但是此时t1的a是走的索引
所以理论上来说t1一共扫描了100次

a字段是有索引的
做表关联的时候 如果关联字段是大表 的索引字段 此时这种算法叫做[Nested-Loop Join 算法]
关联的条件如果是非索引的  t1 和t2 都是全表扫描
 Extra 中 的Using join buffer (Block Nested Loop)说明该关联查询使用的是 BNL 算法。
t1和t2是全表扫描  t1 此时没有走索引 

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

https://www.cnblogs.com/yufeng218/p/12544941.html
// 详细请看大佬博客
`在这里插入代码片`

猜你喜欢

转载自blog.csdn.net/weixin_43689953/article/details/120981670