前言
针对现在大数据BI可视化大屏数据量过大、接口查询慢导致的页面加载过慢问题的一些解决思路和方案,这个也是影响用户体验最明显的一部分。
前端
1. 减少查询接口
数据合并在同一个接口,浏览器异步请求数量有限,vue的打包插件会合并js也是这个原因。
2. 懒加载
弹窗、tab页这些可以触发时再加载,列表分页查询滚动时查询。
3. 优先加载页面展示内容
4. 减小请求的资源大小,如js、css这些
减少注释,合并资源这些 ,跟1类似,vue打包时也会将注释删除。
5. 优化加载动作
加入加载层,让用户有感知,请求过多时,可以从左至右依次加载。
前端优化的重点-减少请求次数,减小请求资源
后端
大数据主要是查询,所以方案简单来说就两种查询结果放缓存、优化查询sql的查询速度
1. redis缓存
将接口查询结果放到redis里面去,需要设置过期时间。
这里分全量和增量两种策略的,就是有些接口是会带查询条件的,那么你这个接口是存一次数据到缓存里还是存多次数据到缓存,是需要综合考虑的。
全量:将接口最大范围(不带查询条件)的数据集放到redis里面去,key可以直接锁定,过滤条件通过java计算出来,最终返回结果。(优点:方便做缓存预热)
增量:将接口请求参数的hash值作为key,根据key是否存在把接口数据结果存入到缓存,接口查询时可以直接拿到缓存,不需要二次计算。(优点:不做预热的情况下,对内存占用会更低)
注:不做预热的情况下,首次加载的速度主要跟查询sql的查询速度相关。
数据一致性问题:
对于BI来说,去修改业务库数据的频率很低,基本上是每天定时跑存储过程,所以只要在跑完之后淘汰缓存或者刷新缓存即可,即使需要临时跑数据,一般也是直接删除缓存。
当然我也简单介绍一下数据一致性问题的解决方案。
总体来说就两种方案:
方案1. 先更新缓存,再更新数据库;
方案2. 先更新数据库,再更新缓存;
更新缓存的策略也有两种:淘汰缓存(删除缓存)和刷新缓存
对于BI来说,跑存储过程导致直接修改了业务库数据,所以可以锁定了方案2,所以这里需要有个动作来告诉程序,我数据库更新,你快点把缓存也更新了。我这边方案是:
step1:在程序端启动存储过程,同时启动一个监听线程读取跑批日志
step2:存储过程跑完后,存储一条日志入库
step3:监听线程读取到日志后,判断日志是否更新,跑批是否成功,然后执行缓存更新逻辑
其它缓存策略:
1、延时双删策略+设置超时时间(先删缓存-入库-再删缓存)
2、基于mysql binglog 日志进行异步更新缓存(订阅数据库变更日志,再操作缓存)
3、热点数据(或修改较少的常用数据)定时分阶段刷新缓存;增加手动、定时双机制刷新缓存功能(强制刷新缓存功能,即上面BI缓存策略)
2. sql优化
2.1 索引
创建合理的索引,可以加快查询速度,但是不可盲目的创建索引,会占用磁盘空间,也会增加数据修改的开销
索引失效场景:
- 违反最左前缀原则(联合索引,mysql联合主键索引不会失效)
- 索引列被加工(计算、函数和类型转换)
- 使用特殊过滤条件,如>、>=、in、!=、<>、not in、not exist和is null等(可能会造成当前索引列失效或者后续索引列失效)
索引全生效效果 rows=3(有效索引c、v和d)
后续索引失效 rows=4 (有效索引c和v)
当前索引失效 rows=6(有效索引c)
- 使用like过滤条件时,通配符放在了首位 col like '%abc'
- ...
2.2 子查询添加过滤
子查询添加过滤,减少父查询的数据量,特别父查询中有计算、连接情形。
2.3 指定字段
避免使用
select * from table_a
将要查询的字段显示的写出来
select field1,field2... from table_b