欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送!
在我后台回复 「资料」 可领取
编程高频电子书
!
在我后台回复「面试」可领取硬核面试笔记
!文章导读地址:点击查看文章导读!
感谢你的关注!
索引设计实战
接下来根据具体的项目场景来对索引设计进行讲解
在这里以社交网站中的查询推荐好友功能为例,作用主要是根据一些条件查询用户
首先,最基本的,需要根据省份、城市、性别、年龄、爱好、登录时间(7 天内登录)进行筛选,我们先将 SQL 语句中的 where 条件写出来:
where provience = 'xxx' and city = 'xxx' and sex = 'xx' and age >= 18 and age <= 30 and hobby in ('xx', 'xx')
- 索引设计的时机
注意在实际开发项目过程中,设计索引的时机其实并不是在建立数据库表之后就立即设置索引,而是等业务代码完成之后,再根据业务代码去设计索引,通过良好的索引设计让大多数查询都可以走索引!
那我们来看一下根据上边的 where 条件该来如何设计索引
- 联合索引初始设计
首先,索引的设计原则中,建议不要将选择性比较低的列作为索引,比如性别,但是我们的查询条件中无法避免性别的查询,因此可以将选择性比较低的列(性别)放在联合索引中比较靠后的位置
那么对查询推荐好友来说,基本都需要带上 provience、city、sex 三个列作为条件,因此设计的联合索引中,可以将这 3 个列放在比较靠前的位置,可以更好的遵循最左前缀原则,避免索引失效
因此,先将联合索引设置为:(provience, city, sex)
- age 列索引优化
接下来需要对年龄进行查询,而在索引规则中,如果有一个字段使用了范围查询,那么该字段后边的列就不会走索引了,所以一定要将范围查询的列放在索引的最后边
因此 SQL 语句和联合索引都需要进行优化,在 SQL 语句中,将 age 列的范围查询向后移,如下:
where provience = 'xxx' and city = 'xxx' and sex = 'xx' and hobby in ('xx', 'xx') and age >= 18 and age <= 30
联合索引设置为:(provience, city, sex, hobby, age)
- 对 7 天内登录用户的索引优化
接下来,在 SQL 中加上对登陆时间在 7 天以内的用户进行查询的,表中肯定有一个字段 last_login_time,要判断是否 7 天内登录,可以判断 last_login_time 是否大于(当前时间 - 7 天),那么就要进行函数计算,将当前时间减去七天,但是如果使用了函数计算,就无法走索引了,那么怎么办呢?
-- 这里 login_time 应该大于等于 7 天前的时间,这里使用伪代码来写了
where provience = 'xxx' and city = 'xxx' and sex = 'xx' and hobby in ('xx', 'xx') and age >= 18 and age <= 30 and login_time >= (current_time - 7days)
从 SQL 语句的角度来看,这个问题是无法解决了,但是可以从业务的角度来让这个字段走上索引
我们可以给表中单独增加一个字段 last_login_in_7_days
表示该用户在 7 天内是否登录,如果登录了值为 1,否则值为 0,这样判断用户 7 天内是否登录就可以走索引了
联合索引设置为:(provience, city, sex, hobby, last_login_in_7_days, age)
- 对 sex 索引列优化
假设,在查询的时候,没有对 sex 列进行条件查询,那么就会导致不符合最左前缀原则,从而导致 sex 后边的索引都无法使用,这种情况下该怎么办呢?
我们可以通过修改 SQL 语句来解决这个问题,如果不根据 sex 进行筛选,那就通过 in 语句,让 sex 列所有的枚举值都在 in 语句的条件中,让 SQL 可以走 sex 这一列的索引:
where provience = 'xxx' and city = 'xxx' and sex in ('male', 'female') and hobby in ('xx', 'xx') and last_login_in_7_days = 1 and age >= 18 and age <= 30
这种优化方式不仅针对于 sex 列可以使用,而且针对爱好 hobby 列也可以使用,只要将所有枚举值拿到,再加上 in 语句就可以实现
- 使用辅助索引对其他少数查询进行优化
那么通过上边的联合索引 (provience, city, sex, hobby, last_login_in_7_days, age)
就可以抗下平常 80% 的查询了,那么还有剩下的 20% 查询,是不符合普遍情况的
比如只根据性别查询,并且根据用户评分进行排序,这其中涉及的 2 个字段为:sex、score
where sex = 'female' order by score
像这种情况的查询,是无法走我们上边设计的联合索引的(不符合最左前缀原则),通过 sex 进行筛选,会导致筛选之后还会有很多数据,如果不走索引的话进行磁盘排序,会导致性能很差,因此可以再设计辅助索引,让 order by 可以走 score 列的索引,使用索引排序,速度相比于不使用索引排序更快,因此对于这 20% 的非常规查询,可以设置辅助索引来应对!
比如,设计辅助索引为:(sex, score)
,通过 sex 进行过滤,之后根据 score 进行排序,可以通过索引进行排序,相比于不适用索引,性能提升很多!
总结一下,通过索引实战,可以看出大部分的查询都是比较常规的,我们可以去设计一个联合索引来覆盖到 80% 的查询,而对于非常规的 20% 的查询,可以通过设计一些辅助索引来优化性能!