(1)回顾:
通过上面的篇章,已经把索引设计成了 (province,city,sex,hobby,character,age) 这样的一个形式,这么做其实关键是要让最频繁查询的一些条件都放到索引里,然后在查询的时候
如果有些字段是不使用的,可以用in(所有枚举值)的方式去写,这样可以让所有查询条件都用上索引,同时对范围查询的age字段必须放在最后一个,这样保证范围查询也能用上索引。
(2)假设有两个查询条件:
尝试将其中的一个有范围查询 转换成 枚举值字段
假设在查询的时候还有一个查询条件,是要根据用户最近登录时间在7天之内来进行筛选,筛选最近7天登陆过APP的用户,那么实际可能用户表有这么一个字段 latest_login_time,
要是在where条件里加入这么一个 latest_login_time<=7 天内语句,肯定这个是没法用上索引的,因为这里必然会用一些计算或函数,才能进行时间比对。
而且假设查询里还有age进行范围查询,之前说过,范围查询的时候,只有第一个范围查询是可以用上索引的,第一个范围查询后其他范围是用不上索引的,也就是说。SQL语句设计成
(province,city,sex,hobby,character,age,latest_login_time),然后 where xx xx and age>=xx and age <= xx and latest_login_time>=xx,虽然age和latest_login_time都在
联合索引里,但是按规则,只有age范围查询可以用到索引,latest_login_time 始终用不到索引的。
所以这里有一个技巧,在设计表的时候就必须考虑这个问题,此时完全可以设计一个字段为: does_login_in_latest_7_days ,也就是说这个人是否最近7天登录过APP,假设7天内登录
了这个APP,那么这个字段就是1,否则超过7天没登录就是0,这样就把一个时间字段转换为一个枚举值字段。
接下来的解决方案就简化了,可以设计一个联合索引为:(province,city,sex,hobby,character,does_login_in_latest_7_days,age),然后搜索的时候,在where条件里的字段都用索引
来筛选,实际一般来说,where语句里通过上述索引就可以过滤掉大部分的数据,保留小部分数据下来基于磁盘文件进行order by语句的排序,最后基于limit进行分页,一般性能还是比较高的,但有时候
又怕一个问题,万一仅仅使用联合索引里一些基数特别小的字段来筛选呢?
比如基于性别筛选,一下子筛选出所有的女性,可能有上百万用户数据,接着磁盘文件进行排序再分页,这个性能是极差的!
所以针对这个问题,可以针对基数低的字段再加上排序字段单独设计一个辅助索引,专门用于解决where条件里都是基数低的字段,然后还要排序后分页的问题,这样就可以设计一个联合索引为
(sex,score)。此时如果SQL select xx from user_info where sex=’female’ order by score limit xx,xx 此时假设用之前设计的联合索引是根本没法用上索引的。但是如果是我们设计的
(sex,score)索引呢?此时因为where条件里的字段是等值匹配,而且还是等于某个常量值,所以虽然order by 后跟的score字段是(sex,score)索引里的第二个字段,order by没有从索引最左侧
字段开始排列,但是也是可以使用到索引来排序的。因为具体到使用索引层面,会先对where条件里的sex=female在索引树里筛选到这部分数据,接着在sex=’female’的数据里,这些数据实际上都是排列
到一起的,因为在索引里,会按照sex和score两个字段进行排序,所以sex=’female’的数据都是在一块的。
然后找到这部分数据,接着就可以确定,这部分数据肯定是按照score字段进行排序的,此时就可以按照score字段值的顺序,读取limit语句指定的数据分页就出来了。
所以此时针对这种sex低基数的字段的筛选和基于评分排序的语句,整体运行的效率是非常高的,完全可以基于辅助索引来实现,以此类推,完全可以通过对查询场景的分析,用(province,city,sex,
hobby,character,does_login_in_latest_7_days,age) 这样的联合索引去扛下复杂的where条件筛选的查询,此时走索引筛选速度很快,筛选出的数据量较少,接着进行排序和limit分页。
同时针对一些低基数字段筛选+评分排序的查询场景,可以设计类似的 (sex,score)的辅助索引来应对,让他快速定位到一大片低基数字段对应的数据,然后按照索引顺序去走limit语句
获取指定分页的数据,速度同样很快,
(3)总结:
通过这个案例的分析,想必大家能感受到一些针对具体查询的场景来设计你的联合索引和辅助索引的技巧。
核心重点是:尽量利用一两个复杂的多字段联合索引,扛下80%以上的查询,然后用一两个辅助索引扛下剩余20%的非典型查询,保证99%以上的查询都能充分利用索引,就能保证查询速度和性能。
知识点1:时间字段可以加索引,但是要防止字段函数转换查询导致的索引失效如 month(create_time)=7
知识点2:在没有索引的情况下 limit 5,10 这种要取15个以后,然后再取10个嘛?能通过索引直接定位到6到15这个范围的数据嘛?是的,不能,但是可以通过 id > 值 limit 10筛选,所以limit
不适合深度分页。
知识点3:select xx from user_info where age between 20 and 25 order by score 索引:(age,score),age按照区间查询后score本身就无序了,B+树索引页都是有顺序