mysql 200多万_【MySQL】200万数据的优化面试题

本文分析了几个针对200万数据的MySQL优化面试题,包括女性客户数量和平均年薪、不同城市的客户数量和平均年薪、没有特定信息的客户姓名以及不同年龄段的客户平均收入。通过添加索引、调整SQL语句和优化查询策略,讨论了如何提高查询效率。
摘要由CSDN通过智能技术生成

1. 面试题

0e7556b4078a2afc487d12ec85be3fea.png

数据库表结构

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

b3140f6896b8078b611eeb35bd0fdef0.png

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

我们先写出sql语句:select count(*),avg(monthsalary) from customers1 where gender = 0;

8a05110edeb1019a1f367542717955c8.png

这里可以简单的优化一下,因为时间有点长哦!这里需要给字段添加索引

可以试着将俩个sql语句分开来执行,看看问题出现在哪一句

302fff2c3e15aef53075de170988db8a.png

然后我们可以给monthsalary这个字段添加索引在来测试

alter table customers1 add index index_mothsalary(monthsalary);

910105ae252ae25c798ebc6bef6fc3b8.png

在次测试查询时间

会发现其实其实并没有快多少

4a0e2a90f28fbeb5fe6736a038152512.png

在进行一次联合查询

会发现时间就提升了一点点

ed1ef6868947e6027c70f68954e16a50.png

根据索引的规则,我们的索引需要添加在排序,查询,分组中,所以我们可以给gender这个条件加一个索引在进行查询

6aef16cc935bc46c818592da93d9b6ee.png

会发现计算总数据的sql时间已经下来了,但是我们的计算平均年薪的sql语句边的比没有加索引的时间还长

7d815b90cf236fbee267ec6fad1da1c2.png

分析平均月薪这一条语句

我们会发现并没有用到我们设置的mothsalary这个索引,那是因为在优化器执行时会挑选比较合适的索引。所以使用了gender这个索引,导致了回表的操作,所以数据就慢的不要不要的

37970faeef32d9cf99683710973fe8df.png

然后在进行一次联合查询发现时间更长了,这个时候就是因为回表数据太多,所以我们需要把之前设置的索引删除掉,重新规划索引的设置

0bfccfdb9b6ebcff36e1743170dc54ba.png

删除之前创建的所有索引

a18efe33564b6ec52cb438c9b41e97b4.png

在之前我们建立了俩个查询只有gender这个索引的作用能突出点,那么我们就可以考虑一下建立联合索引并进行查询

这个时候会发现已经从刚刚开始的0.84到现在了0.38了,那么这个sql就完成了3886f7bf5e527e098cab9ce6e39577e7.png

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

同样的我们先写出sql语句

select count(*),avg(monthsalary),city from customers1 group by city;

这个语句是修改id在什么之间的数据

update customers1 set city = '渭南' where id between 1000 and 5000;fc8fbf2119a895a043264243811e8489.png

试着给city建立一个索引

c531ff500a630e34c15433622e039948.png

分析加上索引后的查询时间

ab347e6ff39066dd64b968027e40a8dd.png

试着在建立一个联合索引

这个时间也是可以接受的,这个时间最后放到缓存里边不要一直更新3d5133ed9cb0ca3ed6dbf3174a45ed08.png

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

写出sql语句

select name  from customers1 where mobile = 0 or photo = 0 or yearbonus = 0;

为了避免判断失败,我们把数据库的null改为0

先进性一次简单的查询

17fc8a294047eb20ed237ce3b48347e9.png

分析语句没有使用到任何索引

04642c70afa884981f59fc185c9ca563.png

先创建三条单独的索引

f5231148511fd2390d01afefea98cd5e.png

在次进行分析,还是没有使用到索引

5da3835edc12a4116a1160dda7f879db.png

在上面情况下,创建了索引但是没有使用到的原因是,使用了or语句

一般回表数据在30%是可以接受的,但是当这三条语句加在一起的时候,回表的数据达到了150%左右

主要是因为出现多个索引做联合操作是(多个OR条件),对结果的合并、排序等操作需要费大量的CPU和内存资源,特别是当其中的某些索引的选择性不高,需要返回合并大量数据时,查询成本更高。所以这种情况下还不如走全表扫描。

遇到or语句我们可以使用union all来进行优化

但是会发现一个问题那就是我们刚刚创建的索引没有使用得到d207141d2a3297fa92b73a2a96fb4467.png

解释没有使用到索引的原因

我们可以先看看这几个字段的类型,我们在上边是只有yearbonus有索引,其他俩个索引失效了,这个原因是对于字符串类型查询的时候需要带上引号的558792651df4f3e4e9896e0898cbcf7a.png

把引号带上,然后在进行查询,这样就带上了所有的索引

807415a42029ac9e578ad575f85d6086.png

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

删除之前创建的索引eebe93cd332d5837db5bd163b86e3554.png

建立联合索引

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

在次进行分析

我们创建的联合索引都用上了cb21d64fe2c83883d8d0748e7edf6f31.png

但是当查询的时候会发现时间会变得久的不是一点点,所以这一条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>'

)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值