一、前言

最近小农在找工作,因为今年疫情的特殊原因,导致工作不是特别好找,所以一旦有面试电话,如果可以,都会去试一试,刚好接到一个面试邀请,感觉公司还不错,于是就确定了面试时间,准备了一下就去面试了。

第一轮面试是小组组长面试,通过。
第二轮是经理面试也是通过了。
第三轮总监面试,前面都还有模有样,突然画风一转,面试官说:“问你最后一个问题”

面试官:10W条数据,我要从其中查出100条不连续的数据,给你id,来查name和password进行展示,如何才能高性能的去使用?

我:在id上建立聚簇索引,然后用 in id 来缩小表搜索范围,最后 使用条件查询 小于最大id,大于最小id,这样可以让sql速度能够比较快的展示,虽然In的性能比较低
心里活动:雕虫小技,还最后一个问题,这样的问题再来一个吧

只见面试官紧锁眉头,与我心里期待的表情有点不一样啊,难道是哪个环节出了问题?
面试官:这样的性能不能达到最优化的程度,而且如果我给你的最小id是1,最大id是100000呢?

你这就有点杠精了啊,那行吧,你是面试官你说了算
我:既然id已经给出来了,而且只查询两个字段,用聚簇索引那么查询数据是很快的,用in id应该是可以的。

面试官:好的,回去等通知吧
我。。。。。

二、后知

于是回去后,查询资料,才知道原来面试官,真正想考的是 “覆盖索引”

什么是覆盖索引:

当sql语句的所求查询字段(select列)和查询条件字段(where子句)全都包含在一个索引中 (联合索引),可以直接使用索引查询而不需要回表。这就是覆盖索引,通过使用覆盖索引,可以减少搜索树的次数,这就是 覆盖索引,在了解覆盖索引之前,我们先来看看什么是索引。

三、什么是索引?

我们有一个主键列为id的表,表中有字段name,并且在name上有索引

表中 t_user 值分别为(1,张一)、(2,张二)、(3,张三)、(4,张四)、(5,张五)

表结构如下:

mysql> create table t_user (
id bigint(20) not null auto_increment ,
name varchar(255) not null,
primary key (id),
index index_name (name) using btree)
engine=innodb
default character set=utf8 collate=utf8_general_ci

两棵树的示例示意图如下:

从图中不难看出,根据叶子节点的内容,索引类型分为主键索引和二级索引(非主键索引)。

主键索引: 主键索引的叶子节点保存着主键即对应行的全部数据。在InnoDB里,主键索引也被称为聚簇索引(clustered index)。

二级索引(非主键索引): 二级索引树中的叶子结点保存着索引值和主键值,当使用二级索引进行查询时,需要进行回表操作。在InnoDB里,非主键索引也被称为二级索引(secondary index)

通过上面所讲的,我们来看看如何通过sql语句来区分 主键索引和普通索引的查询

  • select * from t_user where id=1 即主键查询方式,则只需要搜索id这棵B+树
  • select * from t_user where name=张三 即普通索引查询方式,则需要先搜索name索引树,得到id的值为3,再到id索引树搜索一次。这个过程称为回表

也就是说,基于二级索引(非主键索引)的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询。

看到这里如果你看懂了上面的介绍,那么这里你会有一个疑问,我直接用in id不就好了吗,建立id主键索引,就可以不用回表了,速度不也就提升了吗?

如果是 5.5 之前的版本确实不会走索引的,在 5.5 之后的版本,MySQL 做了优化。MySQL 在 2010 年发布 5.5 版本中,优化器对 in 操作符可以自动完成优化,针对建立了索引的列可以使用索引,没有索引的列还是会走全表扫描,也就是我们所说的回表。

那么,有没有可能经过索引优化,避免回表过程呢?答应是有的

四、覆盖索引

sql语句如下,其中id自增,name为索引:

mysql> create table t_user (
id bigint(20) not null auto_increment ,
name varchar(255) not null,
password varchar(255) ,
primary key (id),
engine=innodb
default character set=utf8 collate=utf8_general_ci

比如有这么两句sql

语句A: select id from user_table where name= '张三'
语句B: select password from user_table where name= '张三'

语句A: 因为 name索引树 的叶子结点上保存有 name和id的值 ,所以通过 name索引树 查找到id后,因此可以直接提供查询结果,不需要回表,也就是说,在这个查询里面,索引name 已经 “覆盖了” 我们的查询需求,我们称为 覆盖索引

语句B: name索引树 上 找到 name=‘张三’ 对应的主键id, 通过回表在主键索引树上找到满足条件的数据

因此我们可以得知,当sql语句的所求查询字段(select列)和查询条件字段(where子句)全都包含在一个索引中(联合索引),可以直接使用索引查询而不需要回表。这就是覆盖索引

例如上面的语句B是一个高频查询的语句,我们可以建立(name,password)的联合索引,这样,查询的时候就不需要再去回表操作了,可以提高查询效率。

所以关于上面的面试题我们就可以得出,使用联合索引就可以很好的回答面试官的问题(id,name,password)这样的联合索引就可以调用到覆盖索引,可以减少树的搜索次数,不再需要回表查整行记录,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。

说到了联合索引我们就不得不说联合索引中最重要的匹配原则,最左匹配原则了

五、最左匹配原则

最左前缀匹配原则,是非常重要的原则,mysql会从左向右进行匹配。

例如我们定义了(name,password)两个联合索引字段,我们 使用 where name = '张三' and password = '2'索引可以生效的,当我们是颠倒了他们的顺序 使用where password = '1' and name = '王五',索引同样也是可以生效的,在mysql查询优化器会判断纠正这条sql语句该以什么样的顺序执行效率最高,最后才生成真正的执行计划,我们能尽量的利用到索引时的查询顺序效率最高,所以mysql查询优化器会最终以这种顺序(where name = '张三' and password = '2')进行查询执行,就类似 我们的 order by name,password这样一种排序规则,先对张三的用户进行查询排序,在对password进行处理

比如我们要查询姓张的用户,我们的条件查询可以为 "where name like ‘张%’",但是不能是 where name like '%张%'或者是 where name like '%张',因为索引可以用于查询条件字段为索引字段,根据字段值必须是最左若干个字符进行的模糊查询,也就是需要是 ‘张%’ 这样的添加才可以使用。

索引的复用能力。因为可以支持最左前缀,所以当已经有了(name,password)这个联合索引后,一般就不需要单独在name上建立索引了。因此,第一原则是,如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的。

如果既有联合查询,又有基于name,password各自的查询呢?查询条件里面只有password的语句,是无法使用(name,password)这个联合索引的,这时候你需要同时维护(name,password)、(password) 这两个索引。

创建索引时,我们也要考虑空间代价,使用较少的空间来创建索引
假设我们现在不需要通过name查询password了,需要通过name查询age或通过age查询name

  • 1.(name,age)联合索引+age单字段索引
  • 2.(age,name)联合索引+name单字段索引

name字段是比age字段大的,所以,选择第一种,索引占用空间较小的一个

六、索引下推

上面我们说到满足最左前缀原则的时候,最左前缀可以用于在索引中定位记录。那么如果那些不符合最左前缀的部分,会怎么样呢?

如果现在有一个需求:检索出表中“名字第一个字是张,而且没有删除的信息(is_del = 1)。SQL语句如下:

mysql> select * from t_user where name like ‘张%’ and is_del=1

在MySQL 5.6之前,只能从匹配的位置一个个回表。到主键索引上找出数据行,再对比字段值

在MySQL 5.6中 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数

根据(username,is_del)联合索引查询所有满足名称以“张”开头的索引,然后回表查询出相应的全行数据,然后再筛选出未删除的用户数据。过程如下图:

每一个虚线箭头表示回表一次
图一(无索引下推执行流程)

每一个虚线箭头表示回表一次
图二(索引下推执行流程)

图1跟图2的区别是,InnoDB在(name,is_del)索引内部就判断了数据是否逻辑删除,对于逻辑删除的记录,直接判断并跳过。在我们的这个例子中,只需要对ID1、ID4这两条记录回表取数据判断,就只需要回表2次

mysql默认启用索引下推,我们也可以通过修改系统变量optimizer_switch的index_condition_pushdown标志来控制SET optimizer_switch = 'index_condition_pushdown=off';

我们也需要注意:

  • innodb引擎的表,索引下推只能用于二级索引,因为innodb的主键索引树叶子结点上保存的是全行数据,所以这个时候索引下推并不会起到减少查询全行数据的效果
  • 索引下推一般可用于所求查询字段(select列)不是/不全是联合索引的字段,查询条件为多条件查询且查询条件子句(where/order by)字段全是联合索引

六、小结

今天的内容就到这里了,我们在上面描述了数据库索引的概念,包括了覆盖索引、联合索引、索引下推,那么下次如果有面试官问你刚开始的问题,相信大家可以好好的回(dui)答(ta)一下面试官了,在sql优化中,减少回表次数,或者直接使用覆盖索引是比较重要的,尽量少地访问资源也是数据库设计的重要原则之一,谢谢大家,加油~

面试三轮我倒在了一道sql题上——sql性能优化相关推荐

  1. sql三张表的搜索要满足5种搜索条件的模糊搜索_面试三轮我倒在了一道 SQL 题上……| 原力计划...

    作者 | 牧小农的夏天 责编 | 王晓曼 出品 | CSDN博客 前言 最近小农在找工作,因为今年疫情的特殊原因,导致工作不是特别好找,所以一旦有面试电话,如果可以,都会去试一试,刚好接到一个面试邀请 ...

  2. U9在SQL Server上的性能优化经验(转述) — 之 行版本快照

    此文根据用友的文档<基于SQL Server 2008构建SOA大型管理软件技术实践>"翻译"而成,非原创.在baidu上看见此文,觉得写的很好,就将原先的PPT细化一 ...

  3. 在网上看到和篇关于sql server 2005的性能优化篇,觉得写得很好。

    在网上看到和篇关于sql server 2005的性能优化篇,觉得写得很好. SQL Server2005扩展函数已经不是一件什么新鲜的事了,但是我看网上的大部分都是说聚合函数,例子也比较浅,那么这里 ...

  4. 转载SQL Server 数据库的性能优化

    你是否在千方百计优化SQL Server 数据库的性能?如果你的数据库中含有大量的表格,把这些表格分区放入独立的文件组可能会让你受益匪浅.SQL Server 2005引入的表分区技术,让用户能够把数 ...

  5. .Net+SQL Server企业应用性能优化笔记3——SQL查询语句

    在上一篇文章中我们使用了几种方法来确定瓶颈,找到瓶颈,下面再回顾一下: LoadRunner压力测试+Windows计数器,这种方法主要是找出大概的性能问题是在哪台服务器,主要是哪个资源紧张. ANT ...

  6. aws rds监控慢sql_探索AWS RDS SQL Server上SQL Server集成服务(SSIS)

    aws rds监控慢sql In the previous article, Deploy tabular databases in SSAS on AWS RDS SQL Server, we ex ...

  7. Spark SQL运行流程及性能优化:RBO和CBO

    1 Spark SQL运行流程 1.1 Spark SQL核心--Catalyst Spark SQL的核心是Catalyst查询编译器,它将用户程序中的SQL/Dataset/DataFrame经过 ...

  8. 又一道小学题的sql实现~~~

    鬼谷子先生有两个绝顶聪明的门徒,一个叫孙宾(后来改名孙膑),一个叫庞涓. 有一天鬼谷子对他们说:"两个大于1而小于100的自然数相加等于一个和,相乘等于一个积.谁能猜出我说的这两个自然数是多 ...

  9. PostgreSQL in 与 = any 的SQL语法异同与性能优化

    标签 PostgreSQL , in , = any (array()) , hash table , subplan , initplan 背景 数据库SQL也算一门比较神奇的语言了,比如很多需求可 ...

最新文章

  1. python打印汉字宝塔_利用宝塔+python+搭建falsk项目_详(一)
  2. LCUI.css 0.1.2 发布, 基于 LCUI 开发的 UI 组件库
  3. 二极管的反向恢复过程
  4. linux I/O--I/O多路复用--select总结(三)
  5. MySQL ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
  6. Selenium Xpath元素无法定位 NoSuchElementException: Message: no such element: Unable to locate element
  7. 计算机二级web题目(2)--HTTP基础
  8. 安装SQL SERVER 2008时出现了SQL SERVER 2005 Express Tool Installed 的错误
  9. 64位 linux 中 oracle 11g dbca 报 out of memory 错误
  10. 724. 寻找数组的中心索引
  11. 7月29日绝地求生服务器维护,绝地求生7月29日维护到几点 7.29吃鸡更新维护公告...
  12. 服务器如何取得系统管理员权限,技巧:Windows系统如何获得管理员权限?
  13. hive从入门到放弃(一)——初识hive
  14. Android 移动网络接入点名称(APN)
  15. 【问链-区块链基础知识系列】 第十二课 区块链产业落地现状分析
  16. python爬虫---12306获取列车座位信息
  17. 汇编语言的一些相关资料(上机或者实验)
  18. 让Qt程序适配高分辨率屏幕,解决软件界面错乱异常
  19. gitlab自动同步github
  20. 鲁大师3月新机性能/流畅榜:骁龙8对决天玑9000,这款手机拿下两个冠军

热门文章

  1. 或许我只是个小丑罢了
  2. 微信社群机器人Java,做社群一定需要用到微信群机器人吗?看这里你就懂了!...
  3. 白乔原创:程序员的路该怎么走?
  4. MSF实战制作deb软件包后门
  5. html页面加文字怎么加,HTML页面添加文字水印
  6. 传说哥和Meepo之间不为人知的故事
  7. 车床主传动系统设计、臂架优化设计、组合机床设计、风力发电机传动机构的设计、立式数控雕刻机、上下料机械手设计、抹灰机设计、LS型螺旋输送机设计、X-Y数控工作台设计、磨床液压传动系统设计……
  8. 游戏/应用出海本地化策略 | 俄罗斯市场篇
  9. 依赖报错:While resolving: @vue/eslint-config-standard@6.1.oFound: eslint-plugin-vue@8.7.1
  10. 户用光伏市场乱象丛生 恶性竞争影响发展