基于MySql 多表分页查询优化技术

通过逻辑判断避免多表扫描及 union 操作, 根据页面偏移量快速定位查 询所要涉及的表, 从而有效避免不必要的操作, 提高 了查询效率

本算法先根据 指定的条件确定查询所要涉及的分表, 再根据查询条
件算出各个表中符合条件的记录数; 然后将各个分表
中符合条件的记录数相加得到符合条件的总记录数,
从而根据页面大小计算记录总页数. 根据用户页面传
过来的页数计算偏移量, 通过偏移量和页面的大小以
及各个表中的符合条件的记录数做比较, 得出需要返
回给用户的数据存在于哪张表中, 然后从该表中返回
给用户指定偏移量以及指定数量的记录即可.

本算法通过逻辑判断精确地得出了数据所在的表, 使每次查
询只需要查询一张表. 在极端的情况下每个表只有少
量的数据需要查询, 多张表才能获取一页的数据, 通过采用精准的单表查询过滤符合条件的数据返回给用
户. 由于当符合条件的数据量比较小时执行计划会合
理利用内存操作以获得较高的查询效率. 通过以上分
析可以看出, 本算法避免了不必要的多表扫描和union.

http://www.c-s-a.org.cn/csa/ch/reader/create_pdf.aspx?file_no=20160830&flag=1&year_id=8&quarter_id=

原文下载:

秒杀服务限流策略

合法性限流:拦截非法请求;负载限流:使用集群实现负载均衡;服务限流:配置服务器&限流算法&MQ等中间件&缓存&监控等

一、请求抵达服务器前:

  • 合法性限流
    1. IP限制:若同一IP短时间内(如毫秒级)下单,或重新购买同一件商品,可认定为机器人刷单或不合法用户,可通过NGINX的IP黑名单做限制;
    2. 隐藏入口:秒杀活动开始时,才开放真正的秒杀入口地址;
    3. 验证码:通过要求输入验证码,可以拉长用户请求时间,降低峰值。
  • (软)负载限流
    1. 集群:Nginx(& LVS)
    2. 网络七层模型:第七层「应用层」——Nginx做负载;第二层「数据链路层」——通过虚拟MAC映射多台服务器;第三层「网络层」——IP负载;第四层「传输层」——端口号负载(LVS)。
    3. 建议使用Nginx,或Nginx+LVS做两层负载即可。(过多级联负载,增加转发路径,有网络延迟风险)
    4. 注,硬件负载:F5, Array

二、请求到达服务器:

  • 服务限流
    1. web服务器限流:如tomcat设置最大请求数,超过的请求会被无条件拒绝;
    2. 算法限流:令牌桶算法、漏桶算法(如Google Guava类库)
    3. 消息队列:不同子系统根据自身处理能力从消息队列中获取适量请求做处理;
    4. 缓存限流:静态缓存——Nginx对静态文件做定向缓存转发(OSS,CDN);动态缓存——优先使用本地缓存(如 Guava Cache),其次使用远程缓存(如 Redis集群);注:缓存层级不宜过多,建议静态缓存+二级动态缓存即可。
    5. 监控限流:监控服务资源,若资源不足时,降级处理。如使用专门线程监控CPU,若CPU资源不足时,可以降级部分请求,像关闭”三个月之前的订单查询”等非核心服务,待CPU资源缓解时再开启。

做支付、订单相关功能时的注意点

不确定的一定要采取保守策略,不可以直接设置最终态。

  1. 调用第三方支付接口时,若出现网络异常,则记为「处理中」,而不是「处理失败」;
  2. 查询订单失败时,不能作为「交易失败」;
  3. 使用第三方服务时,确保「幂等」下才可重试;(如流水号可以确保幂等时,可以通过流水号不变来重试)
  4. 较短时间内查询第三方订单不存在或失败时,不能想当然认为订单失败,可能是第三方还没处理结束,要延长处理频次或人为干预,确保自己系统的健壮性;
  5. 后端防重时,可以采用有限状态机模式(数据库乐观锁+白名单);
  6. 状态尽量是单向流转(如已完成的订单,不可再变更为处理中)。

简言之,不确定的一定要采取保守策略,不可以直接设置最终态。

Mysql使用虚拟列建索引提升查询性能

使用虚拟列绕过最左匹配,减少查询行数,提升性能

假设有一张t_people表,有组合索引(name, age),若name是「李」开头的有许多,则以下查询依然会很慢:

select * from t_people where name like '李%' and age = 8;

解决方法:可以创建一个「虚拟列」(Mysql 5.7+版本支持)name_first,存储name的第一个字,并使用此虚拟列建组合索引:

alter table t_people add name_first varchar(2) generated always as (left(name, 1)), add index(name_first, age);

修改后的查询语句:

select * from t_people where name_first = '李' and age = 8;

Laravel中Chunk使用注意事项

在数据集较大时,使用chunk分块处理可以防止内存溢出,但若更新内容跟分块依赖字段一致,则会出现更新不完整现象。

简单描述原因:chunk内部机制会对依赖字段分页查询,但每处理过一个数据块,数据集会重新拉取,但此时分页的页码却在正常递增,此时会出现部分数据取不到现象。

详细参考:https://segmentfault.com/a/1190000015284897