当前位置: 首页 > 科技观察

MySQL:连Explain的Type都不知道,怎么能说你精通SQL优化呢?

时间:2023-03-12 08:38:47 科技观察

我们在使用SQL语句查询表数据时,提前使用explain进行语句分析是一个非常好的习惯。通过explain输出sql的详细执行信息,可以针对性的优化sql。今天我们就来分析一下explain中11种不同类型的含义和应用场景。1、系统应用场景:表中只有一条数据,存储引擎可以准确统计这条数据。系统一般出现在MyISAM和内存表查询中。由于我们一般使用的存储引擎是InnoDB,所以这种系统很少用到。2.const应用场景:通过主键或者唯一索引等值查询定位到一条数据。例如:select*fromtestwhereid=1。我们知道MySQL底层使用B+树来存储数据。它的结构可以大致类似于下图。然后我们在m字段上创建唯一索引约束。如果我们要找到m=103的记录,只需要简单的两步,通过二分法定位到m=103。即100->102->103。即使是真实的有很多记录的业务表,由于B+树的chunky结构,在唯一索引中定位一条记录的速度也是非常快的。可以大致认为查询速度是恒定的。因此,MySQL将这种唯一索引或主键(主键也是唯一索引)等价匹配查询定义为const(常量级别)。需要注意的是,由于唯一索引中允许有多个空值,如果对唯一索引进行空值查询,则不能使用const。3、eq_ref的应用场景:在进行多表连接查询时,被驱动表通过主键或唯一索引键进行等值查询。例如:SELECT*FROMt1LEFTJOINt2ONt1.id=t2.id。4、ref的应用场景:普通二级索引等值查询。例如:select*fromt2wherekey2=4。除了唯一索引,我们还会使用更常见的二级索引。由于二级索引,可能会查询到多个匹配值,比const性能差一点。MySQL将这种类型的查询定义为ref。上面我们提到,由于唯一索引中可能存在多个null,所以不能使用const。对于select*fromt2wherekey2为null,不管是唯一索引还是普通索引,最多使用ref的类型。5.ref_or_null应用场景:命中索引时,查询条件除了等价查询外,还包括空值查询。例如:select*fromt2wherekey2=4orkey2isnull。其实看名字就很容易理解。MySQL会在B+树上找到key2=1和key2为null这两条记录范围值,然后得到主键id返回表中查询相关信息。6、index_merge应用场景:查询条件可以命中多个索引。例如:select*fromt3wherekey1=3orkey2=4。索引合并其实很容易理解。当查询条件可以命中多个索引时,MySQL会尝试在两个索引树中寻找匹配条件,然后将结果合并。7、unique_subquery应用场景:查询条件包含子查询,子查询的列可以与主键等价匹配。例如:SELECT*FROMt2WHEREt2.key2IN(SELECTidFROMt3WHEREt2.key2=t3.key2)ORt2.key2=1。通过查看MySQL优化执行SQL,可以看到MySQL优化了in子查询进入存在语句,并在主键索引上执行等效查询。MySQL优化语句:/*select#1*/select`dbs`.`t2`.`id`AS`id`,`dbs`.`t2`.`key2`AS`key2`from`dbs`。`t2`where((`dbs`.`t2`.`key2`,(((`dbs`.`t2`.`key2`)int3onPRIMARYwhere((`dbs`.`t2`.`key2`=`dbs`.`t3`.`key2`)and((`dbs`.`t2`.`key2`)=`dbs`.`t3`.`id`)))))或(`dbs`.`t2`.`key2`=1))。8.Index_subquery应用场景:查询条件包含子查询,通过索引可以等价匹配子查询的列。例如:SELECT*FROMt2WHEREt2.key2IN(SELECTkey1FROMt3WHEREt2.key2=t3.key2)ORt2.key2=1。index_subquery和unique_subquery的区别在于子查询中的列是唯一索引还是普通二级指标。9.范围应用场景:命中某个索引时,在一定范围内查询结果。例如:select*fromt3wheret3.key1>1andt3.key1<3。在实际业务场景中,对列进行范围查询还是很常见的。10、索引应用场景:直接对一个索引树进行条件判断,不需要回表。例如:从t3中选择t3.key1,其中t3.key2=6。当我们创建联合索引idx_key1_key2(key1,key2)时,当判断条件key2=6时,虽然不满足索引的最左前缀原则,但是我们可以遍历idx_key1_key2的索引树,找到key2=6的记录.由于查询结果需要的key1在这个联合索引上,不需要回表,此时可以使用索引。相对而言,索引的性能相对较慢。11.all应用场景:直接遍历整个聚集索引。例如:从t1中选择*。当MySQL无法通过where条件匹配到合适的索引时,或者因为全扫描成本较低时,MySQL会选择all类型进行全表扫描。这种方法也是最不推荐的。最后,一般来说,我们在查询的时候,查询类型可以分为两类:全扫描和索引查询。索引查询又可以细分为:唯一索引等价查询。普通索引等价查询。正常的索引范围查询。扫描整个索引树。对于一个查询SQL,虽然不同查询类型的结果可能相同,但其性能可能相差很大。不同类型的性能从强到差:system>const>eq_ref>ref>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>all。建议大家在写sql的时候使用explain来分析,尽量优化代码。只有不断的练习,才能让自己的sql能力越来越强。