ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

面试官:系统一个查询功能很慢你会怎么做?

2022-01-19 23:02:01  阅读:126  来源: 互联网

标签:面试官 查询 索引 key mysql 很慢 table ref


和很多同行一样,在之前被面试的生涯中,我也遇到过这个问题。只是不同的面试官问法稍有不同,最直接的就是问怎么做sql的优化。

如果是工作一两年内的话,可能多半都会如是回答

1,看表有没有建索引,没有的话建索引

2,建索引要注意作为where查询条件的字段适合建索引

3,区分性不强的字段不适合建索引

4,查询的字段或者数据太多可以减少查询字段或者数据,就是不查询多余的列与行

。。。

这些都没错,但是面试官可能更想听到的应该是关于sql执行计划的。

以mysql为例,官方文档是这么描述的

 

mysql的中文文档有很多,但是翻译了之后转了又转,有时候可能不是那么准确,谷歌直接翻译很多句子都不通,所以我们尝试看看原版官方文档。全当是学习技术的同时学点英文了。

简单翻译如下:

第一段:explain语句提供了一些关于mysql执行语句的信息,explain可以和select,delete,insert,replace,update语句一起使用。

第二段:explain 返回关于select语句中用到的每个表的一行信息。explain会在输出中按照mysql执行语句时读取的顺序列出用到的表。
mysql用嵌套连接方法来解析所有的连接语句。也就是说mysql从第一张表读取一行数据,然后又会在第二张表,第三张表读取
匹配的行,依此类推。当所有的表都处理完之后,mysql会输出选择到的列,并通过表列表回溯,找到匹配行数最多的表。
然后从这张表读取下一行,继续同样的方法处理下一张表。
第三段:explain的输出信息包含分区信息。此外,对于select语句而言,explain还会产生一些扩展信息,只需要在explain之后用SHOW WARNINGS即可显示。
第四段:在mysql早期发行版中,分区信息和扩展信息可以用EXPLAIN PARTITIONS 和 EXPLAIN EXTENDED来显示。

基于向后兼容性,后期的版本仍然识别这些语法,但是分区信息和扩展信息现在默认是开启的,所以PARTITIONS 和
EXTENDED关键字是多余的并且过时了。他们的使用会引起警告。在未来的mysql发行版本的语法里面很可能会被移除。
第五段:过时的PARTITIONS 和 EXTENDED关键字不能在同一个explain语句中使用。此外,这两个关键字都不能和FOMAT选项一起使用。

 

几点小说明:

1,增删改查语句我们都熟悉,replace可能会有点陌生。

replace具备替换拥有唯一索引或者主键索引重复数据的能力,也就是如果使用replace into插入的数据的唯一索引或者主键索引与之前的数据有重复的情况,将会删除原先的数据,然后再进行添加。
语法:replace into table( col1, col2, col3 ) values ( val1, val2, val3 )

2,mysql8.0确实已经移除PARTITIONS 和 EXTENDED语法

 

下面看看explain的输出列

 

 

我们执行explain语句输出的就是这12列,那么12列我们要全部搞明白吗?个人觉得没必要,搞清楚最主要的三个列就好了,其他的就大概知道是啥,面试能说出这三个其他的答不出来也没多大事,要学的要记得东西太多了,没必要花太多时间在这

 

 

一  type

这句是说:explain输出的type列描述了表之间是如何连接的。在上面那个表里面json格式的输出中,join type就是access_type属性的值。下面的列表描述了连接类型,按照最佳到最差排的序

篇幅原因,我直接翻译了,当然,会遵循官方文档的意思。感兴趣又没看过官网的可以自己去看看:https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

 

1 system

表只有一行(=系统表),这是const连接类型的特例


2   const
表最多只有一个匹配行,在查询的开始就就读到了。因为只有一行,这一行的值会被优化器其他部分认为是常量。const是非常快的
,因为只会读一次。
当我们拿主键索引或者唯一索引跟常量值比较的时候就会用到const。下面这个查询中,tb1_name会被当做const表
SELECT * FROM tbl_name WHERE primary_key=1;
SELECT * FROM tbl_name
WHERE primary_key_part1=1 AND primary_key_part2=2;

 

3 eq_ref

对于前面表的所有记录而言,这个表只有一行能与之形成组合。除了system和const类型,这是最好的连接类型。当一个索引的
所有部分都被连接用到了,并且索引是PRIMARY KEY 或者 UNIQUE NOT NULL索引的时候,就会用到eq_ref
eq_ref可以用于等号操作符比较的索引列。比较的值可以是常量或者使用在此表之前读取的表中的列的表达式。下面的例子当中,
mysql用了eq_ref连接处理ref_table
SELECT * FROM ref_table,other_table
WHERE ref_table.key_column=other_table.column;
SELECT * FROM ref_table,other_table
WHERE ref_table.key_column_part1=other_table.column
AND ref_table.key_column_part2=1;

 

4  ref

对于前面表的所有记录,和索引值匹配的行都会读取。如果连接只用了索引的最左前缀或者说索引不是主键索引,也不是唯一索引
(换句话说,根据给的索引值不能选出唯一行记录),就会用到ref。如果给的索引值只会匹配到少量行,那么就算是比较好的连接
类型。
如果用=或者<=>操作符对索引列进行比较就会用到ref。下面的例子中,mysql会用ref连接处理ref_table。
SELECT * FROM ref_table WHERE key_column=expr;

SELECT * FROM ref_table,other_table
WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table
WHERE ref_table.key_column_part1=other_table.column
AND ref_table.key_column_part2=1;

 

5  fulltext
当用全文索引的时候就会用到fulltext连接


6 ref_or_null
这个连接类型和ref类似,但不一样的是mysql会进行额外的行搜索,即使这些行包括空值。这个连接类型优化多半是用在解析子查询中
。下面的例子中,mysql会用ref_or_null连接来处理ref_table。
SELECT * FROM ref_table
WHERE key_column=expr OR key_column IS NULL;

 

7  index_merge
这个连接类型表示用到了索引合并优化。这种情况下,输出行的索引列会包含用到的全部索引,并且key_len包含了用到的索引的最大长度。


8  unique_subquery

在一些in格式的子查询中,这种连接类型会取代eq_ref,比如

value IN (SELECT primary_key FROM single_table WHERE some_expr)
unique_subquery只是一个索引查询功能,目的是完全替换子查询,提高查询的效率。


9  index_subquery
这个连接类型和unique_subquery相似。它会取代in子查询,但只是在下面格式的子查询中非唯一索引时有效。
value IN (SELECT key_column FROM single_table WHERE some_expr)


10  range
通过索引去查找行的时候,只有给定范围的行会被检索到。输出的索引列表示哪个索引被用到了。key_len包含了用到的索引最长的部分。
这种连接时ref列是空。
用=, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, LIKE, 或者 IN操作符当中任意一个,将索引列和常量进行比较时,会用到range。

SELECT * FROM tbl_name
WHERE key_column = 10;

SELECT * FROM tbl_name
WHERE key_column BETWEEN 10 and 20;

SELECT * FROM tbl_name
WHERE key_column IN (10,20,30);

SELECT * FROM tbl_name
WHERE key_part1 = 10 AND key_part2 IN (10,20,30);

 

11   index
index连接类型和all连接类型是一样的,只是多了一个扫描索引树。两种情况下会出现:
1,如果索引是用于查询的覆盖索引,并且能够满足所有表中需要的数据,追回扫描索引树。这种情况下,extra列会显示using index。
仅索引扫描通常比全表扫描更快,因为索引通常都比数据要小。
2,按照索引的顺序,通过索引进行全表扫描查找数据。这时在extra列不会有uses index。
当查询只用到单值索引的列时,mysq会用到这个连接类型。


12  all
对于前面的所有表记录的行组合,会进行全表扫描。如果该表是第一个未标识const的表,这样就不太好了,甚至是非常糟糕的。
通常我们可以通过增加索引来避免全表扫描,这些索引会使得mysql通过常量值或者更早扫描的表的列值检索到当前表的记录。

 

一般来说,要保证查询达到range级别,最好达到ref

 

二  key

这一列表示mysql实际采用哪个索引来优化对该表的访问。如果没有使用索引,则该列是 NULL。如果想强制mysql使用或忽视possible_keys列中的索引,在查询中使用 force
index、ignore index

 

三   extra

关于这一列,我们先看看官网这段话

 

 简单翻译:explain的extra列输出包含了一些关于mysql如何解析查询语句的额外信息。下面的列表逐一解释了这一列可能出现的值。

每一项也都是也都是代表一个json格式的输出,其属性为extra的值。其中一部分的属性展示比较具体。其他的以信息文本属性展示。

如果我们想要让查询更快,就要小心extra列的值为Using filesort 和Using temporary,或者,会以json格式的explain输出,因为
using_filesort 和 using_temporary_table 的值和属性是一样的。

 

 这一列的值官网有很多,列了三四十个,有兴趣自己去看看。我们也只需要熟悉下面常见的几个就行了

 

1  Using index:使用覆盖索引

覆盖索引定义:mysql执行计划explain结果里的key有使用索引,如果select后面查询的字段都可以从这个索引的树中
获取,这种情况一般可以说是用到了覆盖索引,extra里一般都有using index;覆盖索引一般针对的是辅助索引,整个
查询结果只通过辅助索引就能拿到结果,不需要通过辅助索引树找到主键,再通过主键去主键索引树里获取其它字段值

官网是这样说的

 简单翻译:只通过索引树信息就能从表里面检索到需要的列信息,而不需要额外的搜索实际行数据。当查询只用到单个索引的一部分时会用到这个策略。

对于存储引擎为innodb的有用户定义的聚集索引的表,只有当extra列没有出现using index时才会用到索引。连接类型为index而索引为主键,就是这种情况。

 

2  Using where:使用 where 语句来处理结果,并且查询的列未被索引覆盖

 简单翻译:where子句用于限制哪些行与下一个表匹配或者哪些行可以发送给客户端。如果extra值不是using where 并且表的连接类型是all或者index,我们的查询语句可能会有错误,除非我们就是想要获取所有行。

Using where在 JSON 格式的输出中没有直接对应的部分。 attached_condition属性包含WHERE使用的任何条件。

 

3  Using index condition:查询的列不完全被索引覆盖,where条件中是一个前导列的范围

 

 简单翻译:读表的时候通过访问索引元组并测试,再决定是否需要读取全表。这样的话,索引就等于用来推断(‘下推’)读取全表记录,除非确实有必要。

 

4  Using temporary:mysql需要创建一张临时表来处理查询。出现这种情况一般是要进行优化的,首先是想到用索引来优化。                      

 

 简单翻译:为了解析查询语句,mysql需要创建一个临时表存储结果。这种情况多半发生在查询语句包含group by 和 order by子句,而子句的列以不同方式列出。

 

5  Using filesort:将用外部排序而不是索引排序,数据较小时从内存排序,否则需要在磁盘完成排序。这种情况下一 般也是要考虑使用索引来优化的。

简单翻译:mysql 必须做一个额外的过程才能按指定顺序检索行记录。根据连接类型遍历所有行进行排序并存储排序的key,从而指向匹配wehere语句的行。

然后按排好的顺序存储key并检索行记录。

 

6  Select tables optimized away:使用某些聚合函数(比如 max、min)来访问存在索引的某个字段

简单翻译:优化器认为 1)最多只返回一行记录,2)要生成这一行,就要读取确定的一组记录。如果要读取的行在优化阶段就能读取,就没有必要等到执行查询语句时再去读。

当查询被隐式分组(包含聚合函数但没有 GROUP BY子句)时,第一个条件会满足。当每个使用的索引执行一次行查找时,会满足第二个条件。读取的索引数决定了要读取的行数。

 

虽然直接读的官方文档,很多概念还是比较抽象的,毕竟这块内容是有些难度的,只能慢慢的理解并在实践中体会。

 

学无止境,让学习成为一种习惯。

本人水平有限,有不对的地方请指教,谢谢。

标签:面试官,查询,索引,key,mysql,很慢,table,ref
来源: https://www.cnblogs.com/guangwenyin/p/15816136.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有