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

您的SQL是否仍在查询回表?赶紧给它排个覆盖指数

时间:2023-03-16 18:36:03 科技观察

本文转载自微信公众号《飞翔的小牛》,作者小牛。转载本文请联系飞天小牛公众号。什么是回表查询?小伙伴们可以先看看这篇文章了解什么是聚簇索引和辅助索引:AreYouOK?主键、聚集索引和辅助索引。简单回顾一下,聚簇索引的叶子节点包含的是完整的行数据,非聚簇索引的叶子节点存放的是每行数据的辅助索引键+该行对应的聚簇索引键(主键值)数据的。假设有一张user表,包含id(主键)、name、age(普通索引)三列,数据如下:index:Clusteredindex:辅助索引(age):如果查询条件是主键,只需要扫描一次聚集索引的B+树,就可以定位到要查找的行记录。例如:select*fromuserwhereid=7;查找过程如图绿色所示:如果查询条件是普通索引(辅助索引)age,需要先查辅助索引B+树,根据辅助索引keykey得到对应的聚簇索引,然后到聚簇索引B+树中查找对应的行记录。例如:select*fromuserwhereage=28;上面的select*相当于selectid,age,name,right,id是主键索引,age是普通索引,name在age索引的B+树上不存在,所以通过age索引查询后id和age的值,需要去聚簇索引中找name的值。如图,第一步检查age辅助索引:第二步检查聚簇索引:这就是所谓的回表查询,因为需要对索引B+树进行两次扫描,所以很明显它的性能比一次扫描索引树要低。什么是覆盖索引?覆盖索引的目的是避免回表查询。也就是说,通过一个覆盖索引,只需要扫描一次B+树就可以得到需要的行记录。上面已经解释了如何实现覆盖索引。下面的SQL语句需要查询B+树两次:select*fromuserwhereage=28;我们稍微修改一下,让它只需要查询一次B+树:selectid,agefromuserwhereage=28;之前我们的返回结果是整行记录,现在我们的返回结果只需要id和age。什么是身份证?主键索引(聚集索引),什么是age?普通索引(辅助索引),age索引的B+树的叶子节点存储什么?辅助索引键+对应的聚簇索引键所以这条SQL语句只需要扫描一次age索引的B+树就可以了。结合这个例子,不知道大家有没有受到启发,如何实现覆盖索引拒绝回表查询呢?答:联合指数。我们将年龄和姓名设置为组合索引:createindexidx_age_nameonuser(`age`,`name`);此时age和name都和辅助索引key在同一个辅助索引的B+树上,所以只需要扫描一次组合索引B+树就可以得到id、age和name,也就是索引覆盖率和覆盖率索引的常见使用场景。在以下三种场景下,可以使用覆盖索引来优化SQL语句:1)列查询回表优化(如上例中单列索引age升级为联合索引(age,name))2)全表计数查询比如假设user表只有一个索引,就是主键id:selectcount(age)fromuser;可以用explain分析这条语句,如果Extra字段是Usingindex,说明触发了索引覆盖:很明显,现在没有触发覆盖索引,我们来优化一下:将age列设置为索引createindexidx_ageonuser(age),所以只需要查看age索引的B+树就可以得到结果:3)分页查询selectid,age,namefromuserorderbyusernamelimit500,100;对于这条SQL,因为name字段不是索引,所以需要在分页查询中查询回表。使用filesort意味着不使用索引进行排序,或者意味着在索引之外,需要额外的外部排序操作。当你看到这个字段时,你应该意识到你需要优化这条SQL。使用索引覆盖优化:将(age,name)设置为联合索引,这样只需要查(age,name)联合索引的B+树就可以得到结果。