• 【知识积累】关于解决生产Limit导出重复数据的心路历程


    一、现象

    用户大量导出数据,发现数据总量是对的,但是有大量重复数据,且重复的有规律。

    二、实现逻辑

    分区表,id增序,范围分区(less than),分区字段date,保留三十个分区的数据。

    使用了PageHelper

    优化思路:使用拦截器,拦截limit sql进行改写

    原sql:

    select * from table_name where filed1 = '' and filed2 = '' and date >= 'startDate' and date <= 'endDate' limit offset,10000

    优化sql:

    select * from table_name where filed1 = '' and filed2 = '' and date >= 'startDate' and date <= 'endDate' and id >= (select id from table_name where filed1 = '' and filed2 = '' and date >= 'startDate' and date <= 'endDate' order by id limit offset, 1) limit 10000

    通过子查询获取每次分页的第一条记录的id,然后往后查询10000条记录

    利用的是覆盖索引的方式,减少了回表的性能损耗。

    三、头脑风暴

    1、有个同事说limit A,B的用法错误,A是pageSize,B是offset

    在公司私有云查询每次查询的数据的id是一样的,这样就证明了他的想法,他的解释是偏移量始终是B,也就是1(不变),每次取A条记录,往后取10000,不管你的A如何变化,最后每次取的都是第一条记录的id。

    测试发现,公司私有云不支持偏移量,每次返回的第一个id就是一样的,这也是为什么会有后面的2、3、4、5、6.....

    关于limit有两种用法:

    a、limit A, B

    b、limit B offset A

    A:表示偏移量

    B:表示pageSize

    2、怀疑offset计算错误

    测试环境百万数据导出,没有重复

    3、怀疑mysql优化器没有走主键索引

    生产执行explain,索引没有问题

    4、怀疑mysql缓存、版本

    查看开发环境、测试环境、生成环境的mysql版本,以及缓存的参数,是一致的

    5、怀疑mybatis缓存

    查看mybatis源码,二级缓存没有开启,一级缓存计算cacheKey使用了参数这一部分作为生成条件,排除

    6、拿到生产环境每次导出的sql,让运维同学去导出数据,并查看响应的执行计划

    导出的数据没有重复,且执行计划没有问题

    四、最后的办法,导出生产环境对应分区的数据,到开发环境测试

    最后发现8月3号的数据的max id比8月1号的数据的max id要小,上游在推送数据的时候,采用的方案是每天清空数据,全量推送,不保证分区顺序,8月3号的数据推送的时间比8月1号要早,造成了分区内部id有序,整体分区id无序。

    当然,还发现了一个其他的问题,也就是我们只保留30个分区,也就是30天的数据,使用范围分区(less than),没有命中的分区数据,默认归到第一个分区,也就是date小于第一个分区日期的数据,全部插入到第一个分区,造成第一个分区几千万数据,其他分区几十万数据。

    五、mysql的执行计划

    首先会通过子查询确认是哪个分区,然后在满足其他条件的情况下,从排序结果中获取第一条记录的id(正确),然后执行外查询,也是确认分区,从id开始的位置查询满足条件的记录,每次取一万条数据,但是当跨分区查询时,id变的无序的时候,那么就可能每次取到的数据是重复的。

    六、关于limit进一步优化

    可以将每次分页的下一个id传进来,这样就不用子查询了

    注:

    当然也可以,在外层再加order by id,但是会有什么问题呢?

    子查询对所有分区进行了一次排序,外查询又进行了一次排序,性能会受影响。

  • 相关阅读:
    数据分析之金融数据分析
    leetcode 35 python
    基于javaWeb的毕业生论文管理系统——计算机毕业设计
    1.1 计算机组成原理----概述
    vue3学习笔记--1.
    MySQL笔记之Checkpoint机制
    『C语言进阶』字符函数和内存函数(1)
    消息机制篇——初识消息与消息队列
    流量3-------3
    并发之固定运行和交替运行方案
  • 原文地址:https://blog.csdn.net/axin1240101543/article/details/126335127