面试官:如何使用explain来分析SQL执行性能? xunaa 2024-10-05 07:03:54 编辑说 介绍 在工作中,我们捕获性能问题最常用的方法就是打开慢查询,定位执行效率差的SQL。然后当我们找到一条SQL时,我们还没有完成。我们还需要知道SQL的执行计划。比如全表扫描或者 介绍 在工作中,我们捕获性能问题最常用的方法就是打开慢查询,定位执行效率差的SQL。然后当我们找到一条SQL时,我们还没有完成。我们还需要知道SQL的执行计划。比如全表扫描或者索引扫描,这些都需要通过EXPLAIN来完成。 EXPLAIN 命令是查看优化器如何决定执行查询的主要方式。它可以帮助我们深入了解MySQL基于成本的优化器,也可以获取优化器可能考虑的很多访问策略的详细信息,以及优化器在运行SQL语句时预计会采用哪些策略。 下面我们来详细分析一下。准备的数据如下: 课程表 创建表`course` ( `cid` int(3) NOT NULL, `cname` varchar(20) NOT NULL, `tid` int(3) NOT NULL, PRIMARY KEY (`cid`) USING BTREE) ENGINE=InnoDB DEFAULT字符集=utf8mb4; 教师名单 创建表`teacher` ( `tid` int(3) NOT NULL, `tname` varchar(20) NOT NULL, `tcid` int(3) NOT NULL, PRIMARY KEY (`tid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 教师名片表 创建表`teacher_card` ( `tcid` int(3) NOT NULL, `tcdesc` varchar(20) NOT NULL, PRIMARY KEY (`tcid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; id 查询课程号为2或教师证号为3的教师信息 从课程c、教师t、教师卡tc 中选择t.*,其中c.tid=t.tid AND t.tcid=tc.tcid AND ( c.cid=2 OR t.tcid=3 ) 解释完上面的SQL后,如下 如果id值相同,则从上到下依次执行。 为什么要先从t表读取数据,然后与tc表进行表连接,最后与c表进行表连接? (上面的SQL可以改写为join on的形式,执行效果是一样的) 我们写的SQL会被优化器优化。 MySQL 将以小结果集驱动大结果集的方式连接表。表连接是两个表的笛卡尔积,因此连接的顺序是t(3)-tc(3)-c(4),即括号中的数字。如果表数t为5,则连接顺序为tc(3)-c(4)-t(5)。注意,括号中的数字不是表的数量,而是结果集的数量。 如果查询2号课程的老师信息 从课程c、教师t、教师卡tc 中选择t.*,其中c.tid=t.tid AND t.tcid=tc.tcid AND c.cid=2 因为可以确定c的结果集最小,只有一条记录,所以连接顺序为c(1)-t(3)-tc(3) 查询教授SQL课程的老师的描述 SELECT tc.tcdesc FROM Teacher_card tc WHERE tc.tcid=(SELECT t.tcid FROM Teacher t WHERE t.tid=(SELECT c.tid FROM course c WHERE c.cname='sql' ) ); 该SQL先查询c表,然后查询t表,最后查询tc表。运行解释看看。 id值不同。 id值越大,执行优先级越高。将上面的SQL改成下面的形式 SELECT tc.tcdesc FROM Teacher t, Teacher_card tc WHERE tc.tcid=t.tcid AND t.tid=( SELECT c.tid FROM course c WHERE c.cname='sql' ) id值可以相同也可以不同。 id值越大,优先级越高。如果id值相同,就会按照从上到下的顺序执行。 select_type SIMPLE:查询不包含子查询和UNION 从老师那里选择* PRIMARY:查询有任何复杂的子部分,则外部部分被标记为PRIMARY SUBQUERY:SELECT 列表中的子查询中包含的SELECT(换句话说,不在FROM 子句中)被标记为SUBQUERY 查询教授SQL课程的老师的描述 SELECT tc.tcdesc FROM Teacher_card tc WHERE tc.tcid=(SELECT t.tcid FROM Teacher t WHERE t.tid=(SELECT c.tid FROM course c WHERE c.cname='sql' ) ); DERIVED:DERIVED 值用于表示FROM 子句的子查询中包含的SELECT。 MySQL将递归执行它并将结果放入临时表中。服务器内部将其称为“派生表”,因为临时表是从子查询派生的 SELECT cr.cname FROM ( SELECT * FROM course WHERE tid IN ( 1, 2 ) ) cr id为1的表的表名是derivative2,表示它是一个派生表。派生表来自id 2的执行过程。 UNION:UNION 中的第二个及后续SELECT 被标记为UNION。第一个SELECT 被标记为好像它是作为外部查询的一部分执行的。这就是为什么下面第一个示例中UNION 中的第一个SELECT 显示为PRIMARY。如果FROM 子句中的子查询包含UNION,则其第一个SELECT 将被标记为DERIVED,这是下面的第二个示例 UNION RESULT:用于从UNION 的匿名临时表检索结果的SELECT 被标记为UNION RESULT SELECT * FROM course WHERE tid=1 UNION SELECT * FROM course WHERE tid=2 SELECT cr.cname FROM ( SELECT * FROM course WHERE tid=1 UNION SELECT * FROM course WHERE tid=2 ) cr type 索引类型,优化类型的前提是有索引。 Type类型有很多,这里就不一一介绍了。我就介绍几个常用的,性能会从最好到最差。 常量,systemeq_refrefrangeindexall 其中system和const只是理想情况,实际上可以实现refrange。 system:只有一条数据的系统表,或者派生表中只有一条数据的子查询 SELECT a.tname FROM ( SELECT * FROM Teacher t WHERE t.tid=1 ) a const:只能查找一条数据的SQL,用于主键或唯一索引。如果只能找到一条数据,但条件列上没有主键或唯一索引,则不是const。 从老师t 中选择*,其中t.tid=1 如果我们去掉tid上的主键(本例只是临时更改),执行下面的语句,结果如下 从老师t 中选择*,其中t.tid=1 此时type为ALL,验证了我们的想法,虽然只有一个结果,但是条件列上没有主键或唯一索引,也不是const eq_ref:唯一索引。对于每个键查询,返回匹配的唯一行数据(有且只有一个,不能多,不能0)。常见于唯一索引和主键索引。没有必要有索引。这里是我的句子There is no index added to the tcid field in the Teacher 表的一个例子。当然,我的数据太简单了,所以eq_ref可以出现,无需索引。 从教师t、教师卡tc 中选择t.tcid,其中t.tcid=tc.tcid 我们看一下这个表中的数据 教师名单 教师名片表 此时,将针对teacher表的tcid键返回唯一一条数据,因此类型为eq_ref。如果我们在teacher表中添加一条数据(本例只是临时更改),teacher_card表将保持不变,数据如下 教师名单 重新执行上面的SQL 从教师t、教师卡tc 中选择t.tcid,其中t.tcid=tc.tcid 可以看到类型变成了ALL,因为对于教师表来说,键4返回0条数据,并不是每个键值都返回1条数据。 在上面的示例中,为了严谨起见,teacher_card 保持不变。如果向teacher_card表添加数据,然后执行eq_ref的两个示例,实际上没有影响,因为eq_ref可以为teacher key返回唯一的行。数据 ref:非唯一索引,对于每个索引键查询,返回所有匹配行(0,更多) 如下修改表(仅是本示例的临时更改)。出现了同名张三的老师,并在老师表的姓名列上添加了普通索引,以演示有多条匹配行的情况。 教师名单 SELECT * FROM Teacher WHERE tname='张三' 查询名为张三的老师时,会返回2条数据 range:检索指定范围内的行,where后面是范围查询(Between,=,in有时会失败,从而转换为无索引ALL) SELECT * FROM Teacher WHERE tid 3 索引:这与全表扫描相同,只不过MySQL 按索引顺序而不是行扫描表。 在teacher表的name字段上创建索引(本例只是临时更改) 从老师那里选择名字 为tname 创建索引。当我们只查询tid时,它的值已经在B+树的叶子节点上了。不需要回表查询。可以从索引中得到。由于是非聚集索引,叶子节点存储索引键值。以及索引键值指向的主键 然后,同时检查tname(tname上有索引)和tcid(tcid上没有索引)。 从教师中选择tname、tcid 可以看到类型是ALL,因为从tname索引中无法获取tcid数据,只能通过全表扫描。 现在我们要同时查询tname 和tcid。我们不想回表,只是想通过索引表获取数据。我们应该如何建立索引呢?现在我们可以确定仅索引tname 或仅索引tcid 肯定行不通。那么对tname 和tcid 建立索引怎么样(只是本示例的临时更改)? 执行以下sql 从教师中选择tname、tcid 你可以看到这就是全部。这种情况下,我们就得对tname和tcid建立联合索引,因为只有联合索引才能拿到tname和tcid的值,不需要回表。 再次执行 从教师中选择tname、tcid key 使用联合索引 all:全表扫描 从老师那里选择*,其中tcid=1 possible_keys 可能使用的索引是预测,不准确。 key 实际使用的索引 key_len 索引的长度,用于判断联合索引是否被充分利用,以单篇文章而言 ref 列表是按常量(const)过滤还是按某个表的字段(如果是join)过滤(by key) 首先给教师表的tname字段和课程表的tid字段添加索引。 SELECT c.cid, t.tname FROM 课程c, 老师t WHERE c.tid=t.tid AND t.tname='张三' 第一个是const,表示常量,即张三,第二个是test2.t.tid,表示couse表引用test2库中t(老师)表的tid字段。 rows 此列是MySQL 估计必须读取才能找到所需行的行数。 Extra 使用索引:可以在索引中获取所有需要的数据,而不用从表中获取数据。 using where:如果我们没有读取表中的所有数据,或者仅仅通过索引无法获取所有需要的数据,则会出现Using where消息。 已经有Using index和Using where的例子了。当发生索引覆盖时,会显示Using index,性能得到了提升。出现Usingtemporary和Usingfilesort说明性能损失比较大。 使用临时表:当某些MySQL 操作必须使用临时表时,Extra 信息中会出现“使用临时表”。主要常见于GROUP BY、ORDER BY等操作 使用文件排序:这意味着MySQL将使用外部索引对结果进行排序,而不是按索引顺序从表中读取行。 在teacher表的name字段上创建索引(本例只是临时更改), SELECT * FROM Teacher WHERE tname='张三' ORDER BY tname SELECT * FROM Teacher WHERE tname='张三' ORDER BY tcid 执行以下命令 解释select * from Teacher where name='张三' 解释select * from Teacher where address='Beijing' 问题是,这些key_len是怎么计算出来的呢? key_len key_len 表示索引使用的字节数。根据这个值,可以判断索引的使用情况,特别是在组合索引时,判断是否所有索引字段都被查询使用。 字符串类型 char 和varchar 也与字符编码密切相关。 latin1占1个字节,gbk占2个字节,utf8占3个字节,utf8mb4占4个字节(不同字符编码占用存储空间不同) char 和varchar 也与字符编码密切相关。 latin1占1个字节,gbk占2个字节,utf8占3个字节,utf8mb4占4个字节(不同字符编码占用存储空间不同) 字符类型-当索引字段为char类型时+不能为Null char(n)=n*(utf8mb4=4,utf8=3,gbk=2,latin1=1) 所以上面第一个例子(查询名=张三)的key_len是20*3=60 为了下面描述方便,编码类型默认为utf8 字符类型-当索引字段为char类型时+允许为Null char(n)=n*3+1(允许为空,标记是否为空) 字符类型-索引字段为varchar类型时+不能为Null varchar(n)=n*3+2(变长列,记录当前存储了多少数据) 字符类型-当索引字段为varchar类型时+允许为Null varchar(n)=n*3+1(允许为空)+2(可变长度列) 所以上面第二个例子的key_len(查询地址=北京)为100*3+1+2=303 整数/浮点/时间类型的索引长度 Not Null=字段本身的长度 null=字段本身的长度+1 回顾一下前面的例子,是不是很容易理解呢?对于整数时间类型,小编不会给出示例。你自己写个例子就很容易理解了。 用户评论 作业是老师的私生子 explain 分析真的好重要!好多面试都考这块 有8位网友表示赞同! 陌上花 这个题一直困扰我,希望能好好学习一下 explain 语句啊 有16位网友表示赞同! Hello爱情风 Explain sql执行计划,能了解到数据库优化的一些原理,关键点在于看到索引的使用 有16位网友表示赞同! 浮世繁华 面试官问这个问题的重点是看你是否了解sql慢查询的原因和分析方法吧? 有5位网友表示赞同! 你tm的滚 我准备的时候看了很多资料,感觉 explain 其实就是一个很好的工具,可以让你知道你的 SQL 在数据库里怎么执行. 有6位网友表示赞同! 孤廖 看 explain 分析结果,才知道自己的 SQL 写得好不好。 有7位网友表示赞同! 又落空 对SQL性能优化还是比较感兴趣的,这个题目应该是要考察你是否了解数据表的结构和索引的用法吧? 有5位网友表示赞同! 话扎心 面试的时候要记得结合实际案例分析一下 explain 结果! 有6位网友表示赞同! 隔壁阿不都 我学过explain语句,感觉挺棒的工具. 可以看出sql执行的步骤 和时间复杂度 有19位网友表示赞同! 病态的妖孽 这个就需要看清楚执行计划中的各个组成部分了! 有15位网友表示赞同! 秘密 学习SQL性能优化最重要的一点就是在写 SQL 的时候就要把性能放在考虑范围里! 有10位网友表示赞同! 一笑抵千言 面试官估计就是要看你对MySQL性能优化的理解程度吧? 有8位网友表示赞同! 颜洛殇 要突出 explain 语句能帮助我们分析每一行数据的执行过程吧。 有5位网友表示赞同! 孤街浪途 Explain 分析的话,主要是要看 SELECT 节点的执行方法和所花的代价!这才能判断哪个SQL写得比较好。 有7位网友表示赞同! 淡抹丶悲伤 面试官问这个题目是想让你展示你对数据库优化技术的理解和经验! 有5位网友表示赞同! 炙年 对于 SQL性能问题,我认为不仅要了解explain语句,还要注重查询的结构设计和数据表的设计! 有14位网友表示赞同! 抚涟i 这个题我之前面试过几次了,感觉关键是要明确解释每个节点的执行过程! 有16位网友表示赞同! 快速报名 学生姓名 意向学校 意向专业 联系方式 请输入正确的电话号码 或许你还想看: 面试官:如何使用explain来分析SQL执行性能? “对不起”不是“对不起”,小心别人看你! 英语报告厅| “对不起”就是“对不起”吗? 点赞 免责声明 本站所有收录的学校、专业及发布的图片、内容,均收集整理自互联网,仅用于信息展示,不作为择校或选择专业的建议,若有侵权请联系删除! 大家都在看 上一篇 “对不起”不是“对不起”,小心别人看你! 下一篇 返回列表 大家都在看 面试官:如何使用explain来分析SQL执行性能? 介绍 在工作中,我们捕获性能问题最常用的方法就是打开慢查询,定位执行效率差的SQL。然后当我们找到一条SQL时,我们还没有完成。我们还需要知道SQL的执行计划。比如全表扫描或者 艺考资讯 2024-10-05 “对不起”不是“对不起”,小心别人看你! “熟悉的单词有部分含义”是英语中的常见情况。似乎每一个字都认识,但连在一起却又不知道是什么意思。 这里的“Excuse me for a moment”并不意味着“Excuse me for 艺考资讯 2024-10-05 英语报告厅| “对不起”就是“对不起”吗? 英语报告厅 “对不起”只是“对不起”吗? 英语口语中经常使用“Excuse me”这个短语。在我们看来,这句话也应该意味着“对不起”。然而,事实并非如此! “Excuse me”常用于以 艺考资讯 2024-10-05 “Excuse me”的意思是“对不起”,但是“Excuse you”呢? 众所周知,Excuse me的意思是“对不起”,常用于某些场合表达歉意或打扰对方。 那么,既然你学了这么多年《Excuse me》,你见过《Excuse you》吗?你知道它的含义和具体用途吗?今天 艺考资讯 2024-10-05 英语口语中“excuse me”的4种常见情况。学习日常生活英语。文章最后有惊喜。 引起别人的注意 当我们想要引起别人的注意并询问某事时,我们可以使用Excuse me,意思是“对不起打扰你了,请原谅。”此时Excuse me前重后轻,用降调来吸引别人的注意。例如: 1) 艺考资讯 2024-10-05 对于一分钟情景口语和听力,请使用“Excuse me!”请原谅我! 打扰一下! 1.对不起!请原谅我! 2.对不起,我迟到了。对不起,我迟到了。 *请原谅某人……希望因某事而被原谅。 3.这不是借口!这不是借口! 4.别再找借口了!别再找借口了! *找借口寻找 艺考资讯 2024-10-05 “对不起?”是什么意思?英文的意思是?别把它理解为“打扰我”! 1. 相识 熟人['kwent()ns] 熟人, 偶然认识, 熟人 解析: 熟人鞠躬点头熟人点头熟人示例: 她是我在维也纳的家人的一个偶然认识的人。 她是我们在维也纳的家人的密友。 我与他有一 艺考资讯 2024-10-05 20套单词解析只是尖子生的一张门票。建议收藏 好的形容词, 副词好, 但这是一个形容词,指的是身体状况 他又好了。 2. 艰难,艰难 努力工作, 几乎不 努力工作 我简直不敢相信。 3. 迟到,最近 迟到了,迟到了, 最近最近,最近 我最近没 艺考资讯 2024-10-05 every、no、all、both、never、nor 的用法分析 1) 不定代词是 所有,两者,每个,每个,要么,既没有,更多,一点,很少,很多,很多,另一个,其他,一些,任何,一个,没有和一些,某事,任何事,一切,某人,某人,任何人,任何人,没有,没有人,没有人,没有人,每个人,每个人 艺考资讯 2024-10-05 三张图片阐明了两者之间的异同 今天问题的正确答案是什么?当你看到这些选项时,你是否曾感到困惑?它们的含义其实很相似,但是用法却完全不同。不过不用担心,如果你弄清楚了这四个词的用法,以后做同类型题就可以轻 艺考资讯 2024-10-05