我们在数据查询或者数据导出的时候,经常因为时间跨度过大,降低了导出性能。
为了提高性能,我们往往需要对时间进行切分查询,鉴于此,我们需要对时间段,进行切分。
需要一个工具的时候,不应该是先造轮子,而是先寻找别人已经造好的轮子,我到了java时间切片工具 时间切割 时间切分,但是不是很满意。
因为为了提高查询效率,往往我们也会去缓存查询到结果,例如用时间区间做 key 去缓存。但是如果你的时间切割的不合理就会造成很多缓存无法命中。
为了提高时间切片查询缓存的命中率,我决定花时间去造个轮子。
如果它对你的工作和学习有所帮助,请你不要吝惜你的。
import cn.hutool.core.date.LocalDateTimeUtil;
import lombok.Data;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
public class TimeUtil {
@Data
public static class TimePage {
/**
* 分片查询开始时间
*/
private LocalDateTime startDateTime;
/**
* 分片查询结束时间
*/
private LocalDateTime endDateTime;
/**
* 下一次查询时间
*/
private LocalDateTime nextStartDateTime;
/**
* 查询开始时间
*/
private LocalDateTime beginDateTime;
/**
* 查询结束时间
*/
private LocalDateTime finishDateTime;
}
public static TimePage genHighHitTimePage(TimePage timePage, long interval) {
TimePage newTimePage = new TimePage();
// 分片查询开始时间
newTimePage.setBeginDateTime(timePage.getBeginDateTime());
newTimePage.setFinishDateTime(timePage.getFinishDateTime());
newTimePage.setStartDateTime(timePage.getStartDateTime());
// 是否为第一次查询
boolean isFirstQuery = timePage.getStartDateTime().isEqual(timePage.getBeginDateTime());
// 分片查询结束时间
if (isFirstQuery) {
if ((interval / 86400) >= 1) {
// 间隔超过 1 天 86400s
newTimePage.setEndDateTime(LocalDateTimeUtil.offset(LocalDateTimeUtil.beginOfDay(newTimePage.getStartDateTime()), 1, ChronoUnit.DAYS));
} else if ((interval / 3600) >= 1) {
// 间隔超过1个小时
long hours = newTimePage.getStartDateTime().getHour() + 1;
newTimePage.setEndDateTime(LocalDateTimeUtil.offset(LocalDateTimeUtil.beginOfDay(newTimePage.getStartDateTime()), hours, ChronoUnit.HOURS));
} else if ((interval / 60) >= 1) {
// 间隔超过1分钟
long minutes = newTimePage.getStartDateTime().getHour() * 60 + (newTimePage.getStartDateTime().getMinute() + 1);
newTimePage.setEndDateTime(LocalDateTimeUtil.offset(LocalDateTimeUtil.beginOfDay(newTimePage.getStartDateTime()), minutes, ChronoUnit.MINUTES));
} else {
// 间隔小于1分钟
newTimePage.setEndDateTime(LocalDateTimeUtil.offset(newTimePage.getStartDateTime(), interval, ChronoUnit.SECONDS));
}
} else {
newTimePage.setEndDateTime(LocalDateTimeUtil.offset(newTimePage.getStartDateTime(), interval, ChronoUnit.SECONDS));
}
// 防止分片查询结束时间超过查询结束时间
if (newTimePage.getEndDateTime().isAfter(newTimePage.getFinishDateTime())) {
newTimePage.setEndDateTime(newTimePage.getFinishDateTime());
newTimePage.setNextStartDateTime(null);
} else {
// 分片下次查询时间就是此次查询结束时间
newTimePage.setNextStartDateTime(newTimePage.getEndDateTime());
}
return newTimePage;
}
}
测试:
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN);
String startDateTime = "2023-05-01 11:00:05";
String endDateTime = "2023-05-03 18:23:00";
// 间隔,单位秒
long interval = 86401L;
LocalDateTime startTime = LocalDateTime.parse(startDateTime, dateTimeFormatter);
LocalDateTime endTime = LocalDateTime.parse(endDateTime, dateTimeFormatter);
TimeUtil.TimePage timePage = new TimeUtil.TimePage();
timePage.setBeginDateTime(startTime);
timePage.setFinishDateTime(endTime);
timePage.setStartDateTime(startTime);
timePage.setEndDateTime(endTime);
TimeUtil.TimePage newTimePage = TimeUtil.genHighHitTimePage(timePage, interval);
System.out.println(newTimePage);
while (!newTimePage.getEndDateTime().isEqual(newTimePage.getFinishDateTime())) {
newTimePage.setStartDateTime(newTimePage.getNextStartDateTime());
newTimePage.setEndDateTime(newTimePage.getFinishDateTime());
newTimePage = TimeUtil.genHighHitTimePage(newTimePage, interval);
System.out.println(newTimePage);
}
结果:
TimeUtil.TimePage(startDateTime=2023-05-01T11:00:05, endDateTime=2023-05-02T00:00, nextStartDateTime=2023-05-02T00:00, beginDateTime=2023-05-01T11:00:05, finishDateTime=2023-05-03T18:23)
TimeUtil.TimePage(startDateTime=2023-05-02T00:00, endDateTime=2023-05-03T00:00:01, nextStartDateTime=2023-05-03T00:00:01, beginDateTime=2023-05-01T11:00:05, finishDateTime=2023-05-03T18:23)
TimeUtil.TimePage(startDateTime=2023-05-03T00:00:01, endDateTime=2023-05-03T18:23, nextStartDateTime=null, beginDateTime=2023-05-01T11:00:05, finishDateTime=2023-05-03T18:23)