走进索引,看一看数据库查询(一)

        上一篇文章 简单的说了下数据库索引的结构,接下来当然要看一看索引到底是咋用的,要是建立了索引却没用,那不是太亏了不是?当然,慢一点不要就,就怕进行大批量的操作,数据量又不少,最后一直在加载表数据到缓存,直接把缓存挤爆了,那就惨了,哈哈~

那怎么判断一个查询语句有没有用索引呢?加了索引,难道就会用到?肯定不是啊,背面试题的时候,肯定要记,哦,索引加上左右‘%’会失效,使用聚合函数会失效等等等等。

  那SQL到底用没用索引呢?这个要MySQL来告诉我们。每一个SQL执行前,MySQL会对这个SQL语句进行分析,然后确认查询方式,争取使用最快的速度查询目标数据!而在分析过程中之后,执行之前,自然有个东东,也就是咋执行,书面语就是 执行计划!  好吧,我们先来瞅瞅MySQL的执行计划到底是啥。

首先,先创建两个表。

- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `stu_name` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '学生姓名',
  `stu_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '学生编号',
  `school_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '学校编码',
  `create_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_code`(`stu_code`) USING BTREE COMMENT '学生编码索引'
) ENGINE = InnoDB AUTO_INCREMENT = 1446881 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci COMMENT = '学生表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for teacher
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `teacher_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '教师工号',
  `teacher_name` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '教师名称',
  `school_id` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '学校',
  `create_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `code`(`teacher_code`) USING BTREE COMMENT '教师索引',
  UNIQUE INDEX `name`(`teacher_name`) USING BTREE COMMENT '名称索引'
) ENGINE = InnoDB AUTO_INCREMENT = 42100 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;


-- 多对多,师生关系表
CREATE TABLE `relation`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `teacher_id` int(11) NULL DEFAULT NULL,
  `student_id` int(11) NULL DEFAULT NULL,
  `remark` varchar(40) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `key`(`teacher_id`, `student_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;

创建两个存储过程,批量写数据,写的存储过程比较简单,可以尝试优化存储过程,使用批量插入,插入速度会快很多。我已经插入完成了,就不改了哈。

-- 存储过程插入学生表
CREATE PROCEDURE `batchInStu`( i INT )
BEGIN 
		DECLARE a int DEFAULT 1;
		while a <= i DO
			START TRANSACTION;
			INSERT INTO student(stu_name, stu_code, school_code, create_time) VALUES (CONCAT('张三',a),REPLACE(UUID(),'-',''),20,CURRENT_TIMESTAMP);
			COMMIT;
			SET a = a+1;
			end while;
end

搞定!学生表的话我大概插入了100多万条数据,教师表插入100条数据左右。基础设施建设完毕,正题开始!

        

如上图,查询某个SQL的查询效率,是否使用索引等信息,可以在整个查询语句之前,添加一个单词,explain!

查询的结果,一共有12个字段。

1.id列

这个其实就是查询的序列号,序号越大,执行的优先级越高,相同的话就从上往下执行。这个一般使用多级查询或者关联子查询才会用到。

2.select_type 列

select_type一般分为六种simple,primary,subquery,derived,union和union result。

simple:简单的select查询,查询中不包含子查询或者union。

primary:查询中包含子查询,最外层的查询呗标记为primary。

subquery:表示在select中包含含子查询,举个例子:explain SELECT id ,(SELECT min(teacher_code) from teacher) as num from student where id <25; 这个查询teacher表的select_type就是subquery;

derived:衍生查询,就是在from 后面的子查询,MySQL会将结果放在一个额临时表中,也称为派生表。举栗子:explain SELECT * from (SELECT teacher_code from teacher where school_id >10 ) a

不过大家记得如果是MySQL 5.7以上版本的话,记得关闭一个东东,就是执行这个语句:set session optimizer_switch='derived_merge=off';
,因为5.7以上对衍生表进行了合并优化。

 

union:表示union中的第二个或后面的select语句。

union result:union的结果。

3.table 列

表示这个SQL语句会访问哪张表。

4.type 列

这一列是我们最常用也是和优化SQL关系最大的一列,决定这这个SQL语句在MySQL中如何运行,是否使用索引。依次从最优到最差的级别为:

system>const>eq_ref>ref>range>index>ALL 。通常情况下,需要达到range级别,越往上越好。

system:表只有一行记录,这是const类型的特例。

const:通过索引一次就能找到,一般用于主键索引(一般是id)或者是唯一索引(unique index),只匹配一条数据,读取1次,所以效率特别快。SQL如下:

             

       eq_ref: 唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描。

             

ref:使用普通索引或者是唯一索引的部分前缀(like 也可能使用索引),索引与某个值比较,可能会找到多个符合条件的数据。

       range:返回扫描,通常出现在in,between,大于,小于等操作中。使用索引检索给定的范围。
                

 

    index:扫描索引就能拿到结果,一般扫描的是二级索引,这种扫描直接对二级索引的叶子节点遍历扫描,速度还是比较慢的。不过二级索引一般较小,通常比扫描全表快一些。
              

                 

        5. possible_keys 列

     这一列显示查询可能使用哪些索引来查找。explain是可能出现possible_key有列,而key显示为NULL 的情况,这种情况因为表中数据不多,MySQL认为索引对此查询帮助不大,所以选择了全表查询。

    如果该列是null,则没有相关索引,这种情况下,可通过检查where子查询看是否可以创造一个适当的索引来提高查询性能,然后用explain查看效果。

        6.key列

     这一列显示mysql实际采用哪个索引来优化该表的访问。

      如果没有使用索引,则该列是null,如果想轻质mysql使用或者忽视possible_keys列中的索引,在查询中使用ignore index,force index。

        7.ken_lenlie

        这个是索引使用的字节数,通过这个值可以计算出使用了索引中的哪些列。索引的最大长度是768个字节,如果字符串过长,mysql会做一个类似左前缀索引的处理,并将前半部分的字符提取出来做索引。

       8.ref 列

       这一列显示了在key列记录的索引中,查找到值所用的列或常量,常见的有:const,字段名,

      9.row列

       这一列是mysq估计要读取并检测的行数,但是结果并不一定是这个行数。

      这篇拖延了好久了了,先这样,后面的下面再补充【捂脸】。

   no sacrifice,no victory~

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笔下天地宽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值