MySQL:别跑了好吗?程序员:不跑你就养我?MySQL:听我给你“解释”。程序员:先照顾好自己。不管现在的互联网应用还是传统应用,不管是什么开发语言,说到关系型数据库,MySQL基本上是最好的选择。在Java开发框架中,MyBatis可以自定义SQL,ORM/JPA会根据对象映射自动生成一系列相关的SQL。至于自动生成的SQL,甚至是自定义的SQL,执行效率高不高,不用select*,加where条件,免查全量数据等,我们开发者基本可以用大脑中已有的知识储备,再过滤一遍,至于SQL是否高效执行,我从来没有问过MySQL。其实,SQL语句写完之后,这个工作还不到一半就完成了。剩下的还是要评估我们SQL写的好坏,执行效率是否够高。MySQL就像一个智者,一直都在,只要你问,他都会告诉你一切。重点是,先别急着走,听他解释。Explain在MySQL中,我们一般使用desctableName来查看一个表的信息,各列的定义等,通过ExplainSQL了解MySQL是如何执行当前SQL的。其实desc、describe、explain都可以用来查看MySQL如何执行当前的SQL。MySQL8.0.19之后,这三者的功能可以说是等价的,explain也可以用来查看表信息。后面我们直接以explain为例来说明具体的功能。官方文档明确说明explain可以和SELECT、INSERT、UPDATE、DELETE一起显示MySQL优化器的语句执行计划,用来告诉用户MySQL将如何执行这条SQL,以什么顺序执行,如果有多个Table的话是怎么加入的。输出字段官网文档截图如下:上面的return好像挺多的,但是我们重点关注type、key、rows这三种类型。我们常见的应用场景是读多写少,SQL执行效率的评价一般是指从存储的100条、10万条、甚至几千万条数据中查询所需数据的效率。下面以SELECT为例,看看explain能给我们带来哪些帮助和建议。假设下面的表定义和数据:CREATETABLE`t3`(`id`intNOTNULL,`a`intDEFAULTNULL,`b`intDEFAULTNULL,PRIMARYKEY(`id`),KEY`a`(`a`))ENGINE=InnoDB;分隔符;;createprocedureidata()begindeclareiint;seti=1;while(i<=100000)doinsertintot3values(i,i,i);seti=i+1;endwhile;end;;delimiter;callidata();执行完上面的SQL,我们想到,如果在一个有10万行数据的表中执行一条查询SQL,那么在少量数据中查找肯定比在整个表中查找要快。比如我们最熟悉的通过主键查询selectafromt3whereid=100;你会发现explain里面的type是const,key是PRIMARY。例如执行select*fromt3whereb=100;这时explain告诉我们查询类型是ALL,扫描全表:如果我们想显示这张表的所有数据,就可以了。目前,我们只检查一条数据,而是进行全表扫描。explain告诉我们扫描的行数可能达到9万多行,效率可想而知。如果我们将SQL更改为:select*fromt3wherea=100;这时候explain就变成这样了:你会发现type变成了ref,key变成了a,rows是1,唯一的区别就是一个Index,这时候扫描的行数变成了一行,区别太明显了。如果我们要查找一个范围内的数据,当我们通过主键或包含索引的列进行查询时,扫描仍然是有限的。这个时候type是range,但是如果我们还是用b作为条件去过滤,还是全表扫描:另外,为什么一般的SQL优化建议都说不要用select*,指定具体的列用过的?肯定是哪几列的数据,检查哪些数据省内存和传输。不要等到结果查出来再存入内存另外,更重要的一点是,每个创建的索引都有自己的索引树,查询操作可以在索引树上完成,所以不需要回表查询,效率当然会高一些。例如,我们将查询更改为selecta,idfromt3wherea<100;这时候explain会在Extra中告诉我们,使用查询的时候是没有回表的,如果使用索引的时候查询列变成了star,那么需要回表at这次好吧,让我们像之前所说的那样关注类型、键和行。你可以再看看Extra。类型查询效率从优到差。const表匹配的只有一行,查询一次就够了。常用于匹配主键或唯一索引。eq_refuniqueindexref非唯一索引范围使用索引进行查询,只扫描指定范围内的行。一般搜索列包含=,<>,>,>=,<,<=,ISNULL,<=>,BETWEEN,LIKE,orIN()索引类似于全表扫描,不同的是只索引树是扫描所有全表扫描,效率最低。从MySQL8.0.18开始,增加了explainanalyze,可以查看SQL执行的具体预估时间。比如我们用它来查看上面的命令,会出现如下输出,你会更直观的感受到添加了索引带来的效率提升。很明显吗?那么,你有没有听到MySQL又在跟你说话了?“慢点,小子。”没事的话,我先给你解释一下,再说。”总结一下,通过explain,我们可以在执行前从MySQL优化器得到当前SQL的执行计划,知道执行时至少会扫描多少行,是否会使用索引,大概会用多少时间,等等,以至于要加索引,改SQL,改SQL。这样,应用程序的性能会更加清晰。本文转载自微信公众号“Tomcat物语”,可关注下方二维码。转载此文请联系Tomcat那些东西公众号。
