【MySQL】数据优化---索引---数据200万---面试题

文章目录

    • 1. 面试题
      • 1.1 第一题:女性客户数量和平均年薪
      • 1.2 第二题:不同城市的客户数量和平均年薪
      • 1.3 第三题:列出没有手机号,或者没有照片,或者没有年奖金的客户姓名
      • 1.4 第五题:不同年龄段(0到100岁之间,每10岁为一个年龄段)的客户平均收入

1. 面试题


数据库表结构

 CREATE TABLE `customers1` (
      -- 身份证
      `id` char(20) NOT NULL,
      -- 姓名
      `name` varchar(20) NOT NULL,
      -- 城市名
      `city` varchar(10) NOT NULL,
      -- 性别:1(男),0(女)
      `gender` tinyint(4) NOT NULL,
      -- 出生日期
      `birthdate` date NOT NULL,
      -- 手机号
      `mobile` char(11) DEFAULT NULL,
      -- 照片
      `photo` varchar(20) DEFAULT NULL,
      -- 月薪
      `monthsalary` decimal(10,2) NOT NULL,
      -- 年奖金额
      `yearbonus` decimal(10,0) DEFAULT NULL,
      PRIMARY KEY (`id`)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8

【MySQL】数据优化---索引---数据200万---面试题_第1张图片

1.1 第一题:女性客户数量和平均年薪

  • 我们先写出sql语句:select count(*),avg(monthsalary) from customers1 where gender = 0;
    【MySQL】数据优化---索引---数据200万---面试题_第2张图片

  • 这里可以简单的优化一下,因为时间有点长哦!这里需要给字段添加索引
    可以试着将俩个sql语句分开来执行,看看问题出现在哪一句
    【MySQL】数据优化---索引---数据200万---面试题_第3张图片

  • 然后我们可以给monthsalary这个字段添加索引在来测试
    alter table customers1 add index index_mothsalary(monthsalary);
    在这里插入图片描述

  • 在次测试查询时间
    会发现其实其实并没有快多少
    【MySQL】数据优化---索引---数据200万---面试题_第4张图片

  • 在进行一次联合查询
    会发现时间就提升了一点点
    【MySQL】数据优化---索引---数据200万---面试题_第5张图片

  • 根据索引的规则,我们的索引需要添加在排序,查询,分组中,所以我们可以给gender这个条件加一个索引在进行查询
    在这里插入图片描述
    会发现计算总数据的sql时间已经下来了,但是我们的计算平均年薪的sql语句边的比没有加索引的时间还长
    【MySQL】数据优化---索引---数据200万---面试题_第6张图片

  • 分析平均月薪这一条语句
    我们会发现并没有用到我们设置的mothsalary这个索引,那是因为在优化器执行时会挑选比较合适的索引。所以使用了gender这个索引,导致了回表的操作,所以数据就慢的不要不要的
    在这里插入图片描述

  • 然后在进行一次联合查询发现时间更长了,这个时候就是因为回表数据太多,所以我们需要把之前设置的索引删除掉,重新规划索引的设置
    【MySQL】数据优化---索引---数据200万---面试题_第7张图片

  • 删除之前创建的所有索引
    【MySQL】数据优化---索引---数据200万---面试题_第8张图片

  • 在之前我们建立了俩个查询只有gender这个索引的作用能突出点,那么我们就可以考虑一下建立联合索引并进行查询
    这个时候会发现已经从刚刚开始的0.84到现在了0.38了,那么这个sql就完成了【MySQL】数据优化---索引---数据200万---面试题_第9张图片

1.2 第二题:不同城市的客户数量和平均年薪

  • 同样的我们先写出sql语句
    select count(*),avg(monthsalary),city from customers1 group by city;
    这个语句是修改id在什么之间的数据
    update customers1 set city = ‘渭南’ where id between 1000 and 5000;【MySQL】数据优化---索引---数据200万---面试题_第10张图片
  • 试着给city建立一个索引
    【MySQL】数据优化---索引---数据200万---面试题_第11张图片
  • 分析加上索引后的查询时间
    在这里插入图片描述
  • 试着在建立一个联合索引
    这个时间也是可以接受的,这个时间最后放到缓存里边不要一直更新【MySQL】数据优化---索引---数据200万---面试题_第12张图片

1.3 第三题:列出没有手机号,或者没有照片,或者没有年奖金的客户姓名

  • 写出sql语句
    select name from customers1 where mobile = 0 or photo = 0 or yearbonus = 0;
    为了避免判断失败,我们把数据库的null改为0

  • 先进性一次简单的查询
    在这里插入图片描述

  • 分析语句没有使用到任何索引
    在这里插入图片描述

  • 先创建三条单独的索引
    【MySQL】数据优化---索引---数据200万---面试题_第13张图片

  • 在次进行分析,还是没有使用到索引
    在这里插入图片描述

  • 在上面情况下,创建了索引但是没有使用到的原因是,使用了or语句
    一般回表数据在30%是可以接受的,但是当这三条语句加在一起的时候,回表的数据达到了150%左右
    主要是因为出现多个索引做联合操作是(多个OR条件),对结果的合并、排序等操作需要费大量的CPU和内存资源,特别是当其中的某些索引的选择性不高,需要返回合并大量数据时,查询成本更高。所以这种情况下还不如走全表扫描。

  • 遇到or语句我们可以使用union all来进行优化
    但是会发现一个问题那就是我们刚刚创建的索引没有使用得到【MySQL】数据优化---索引---数据200万---面试题_第14张图片

  • 解释没有使用到索引的原因
    我们可以先看看这几个字段的类型,我们在上边是只有yearbonus有索引,其他俩个索引失效了,这个原因是对于字符串类型查询的时候需要带上引号的【MySQL】数据优化---索引---数据200万---面试题_第15张图片
    把引号带上,然后在进行查询,这样就带上了所有的索引
    【MySQL】数据优化---索引---数据200万---面试题_第16张图片

  • 删除我们之前创建的索引,创建单独的联合索引

    删除之前创建的索引【MySQL】数据优化---索引---数据200万---面试题_第17张图片
    建立联合索引
    如上1,2创建的索引问题不大,3相信很多的疑问,因为这有违背之前所讲的索引挑选的原则,就是优先选择与where 之后的字段作为索引以及最左侧的索引,但是现在选择name为最左侧;这其实在建立的时候我们需要思考当前的这个索引在建立之后可重复用的情况,实际项目操作中我们很少有单独的根据图片去查询用户的信息,更多的时候我们会选择根据用户的某一些信息来查询用户的图片所以在3建立的时候我们需要选择与name作为最左侧查询;【MySQL】数据优化---索引---数据200万---面试题_第18张图片

  • 在次进行分析
    我们创建的联合索引都用上了【MySQL】数据优化---索引---数据200万---面试题_第19张图片

  • 但是当查询的时候会发现时间会变得久的不是一点点,所以这一条sql我们咱们没有更好的方法进行优化

1.4 第五题:不同年龄段(0到100岁之间,每10岁为一个年龄段)的客户平均收入

这条语句的优化方式就不写了,这条的难点就是在于区间查询,由于在填充数据时是随机的,所以这条sql语句没有办法进行查询优化,就把sql写出来了

  • sql语句
    select
    elt(interval(TIMESTAMPDIFF(YEAR, birthdate, CURDATE()), 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100),
    ‘0-10’, ‘10-20’, ‘20-30’, ‘30-40’, ‘40-50’, ‘50-60’, ‘60-70’, ‘70-80’, ‘80-90’, ‘90-100’, ‘100>’
    ) as age_level, avg((monthsalary * 12 + yearbonus)) as income
    from customers1
    group by
    elt(interval(TIMESTAMPDIFF(YEAR, birthdate, CURDATE()), 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100),
    ‘0-10’, ‘10-20’, ‘20-30’, ‘30-40’, ‘40-50’, ‘50-60’, ‘60-70’, ‘70-80’, ‘80-90’, ‘90-100’, ‘100>’
    )

你可能感兴趣的:(Mysql)