隨着項目上線,業務數據會愈來愈多。這個時候,不少開發時適用的方法、任務,在龐大數據量面前就會變得很不堪,常常會出現超時,慢查詢,異常等等問題。數據庫
因此,通常在開發階段,咱們怎麼能避免這些問題呢?一切皆有套路。緩存
通常處理套路:
SQL優化,數據庫加索引,多線程,並行計算,異步處理,大事務拆小事務,緩存,數據異構等等。多線程
今天分享一個經過時間維度優化SQL的方法。說白了,就是如何將時間拆小。異步
仍是直接貼代碼:ide
開始版本,按天拆分時間:大數據
/** * 按給定的天數切割時間段 * @param startDate * @param endDate * @param amount 按多少天切割 * @return * @throws ParseException */ public static List<TimeSlot> splitTimeSlot(Date startDate, Date endDate, Integer amount) throws ParseException { Calendar canlandar1 = Calendar.getInstance();//開始時間 Calendar canlandar2 = Calendar.getInstance();//結束時間 canlandar1.setTime(com.midea.ec.fc.impl.utils.DateUtils.getDateStartTime(startDate)); canlandar2.setTime(com.midea.ec.fc.impl.utils.DateUtils.getDateStartTime(endDate)); List<TimeSlot> returnList = new ArrayList<TimeSlot>(); while(canlandar1.compareTo(canlandar2) < 1){ TimeSlot timeSlot = new TimeSlot(); Date start = canlandar1.getTime(); canlandar1.add(Calendar.DATE, amount);//每次循環增長amount天 Date end = canlandar1.getTime(); timeSlot.setStartDate(DateTool.getDateTime(start)); timeSlot.setEndDate(DateTool.getDateTime(end.before(canlandar2.getTime()) ? end : canlandar2.getTime())); returnList.add(timeSlot); timeSlot.setStartDateTime(start); timeSlot.setEndDateTime(end.before(canlandar2.getTime()) ? end : canlandar2.getTime()); } return returnList; }
發現某些天數據量大跑不動了,而後繼續拆分紅小時:優化
public static List<TimeSlot> splitTimeSlotByHour(String startDate, String endDate) throws ParseException { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); Date date1 = format.parse(startDate); Date date2 = format.parse(endDate); Calendar canlandar1 = Calendar.getInstance();//開始時間 Calendar canlandar2 = Calendar.getInstance();//結束時間 canlandar1.setTime(date1);//2016-11-01 canlandar2.setTime(date2);//2016-11-11 List<TimeSlot> returnList = new ArrayList<TimeSlot>(); while(canlandar1.compareTo(canlandar2) < 1){ TimeSlot timeSlot = new TimeSlot(); Date start = canlandar1.getTime(); canlandar1.add(Calendar.HOUR, 1);//每次循環增長一天 Date end = canlandar1.getTime(); timeSlot.setStartDate(DateTool.getDateTime(start)); timeSlot.setEndDate(DateTool.getDateTime(end)); returnList.add(timeSlot); timeSlot.setStartDateTime(start); timeSlot.setEndDateTime(end); } if(CollectionUtils.isNotEmpty(returnList)) returnList.remove(returnList.size()-1); return returnList; }
最後發現光棍節的這天,小時也跑不動了,還要繼續拆分鐘?改爲本身拆吧。this
/** * @Auther: majx2 * @Date: 2018-11-14 11:24 * @Description: */ public class JobTimeoutHelper { private final Logger logger = LoggerFactory.getLogger(this.getClass()); // 時間區間拆分數量 private int intervalCount = 3; // 拆分最大層級 private int maxCount = 3; private JobTimeoutHelper(){} public static JobTimeoutHelper create(){ return new JobTimeoutHelper(); } public void splitTime(Date startDate,Date endDate,String jobName,TimeSplitHandler handler){ splitTime(startDate,endDate,0,jobName,handler); } public void splitTime(Date startDate,Date endDate,int level,String jobName,TimeSplitHandler handler){ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); if(level>=maxCount){ logger.info("{}超時,拆分已到上限,沒法繼續拆分:時間:{}",jobName,MessageFormat.format("開始時間:{0},結束時間:{1}",df.format(startDate),df.format(endDate))); return; } level++; if(startDate.compareTo(endDate) < 1) { long offset = startDate.getTime(); long diff = endDate.getTime() - offset; long interval = diff/intervalCount; for (int i = 0 ; i <intervalCount;i++){ Date start = new Date(offset); Date end ; if(i == (intervalCount-1)){ end = endDate; }else{ offset += interval; end = new Date(offset); } try{ logger.info("{}處理開始,層級:{},時間:{}", jobName,level,MessageFormat.format("開始時間:{0},結束時間:{1}",df.format(start),df.format(end))); handler.deal(start,end); logger.info("{}處理結束,層級:{},時間:{}", jobName,level,MessageFormat.format("開始時間:{0},結束時間:{1}",df.format(start),df.format(end))); }catch (MySQLNonTransientConnectionException ex){ logger.info("{}超時,進行拆分處理,層級:{}",jobName,level); splitTime(start,end,level,jobName,handler); } catch (Exception e) { logger.error("{}異常啦:{}",jobName, ExceptionUtils.getFullStackTrace(e)); } } } } public interface TimeSplitHandler{ void deal(Date start,Date end) throws Exception; } public JobTimeoutHelper setIntervalCount(int intervalCount) { this.intervalCount = intervalCount; return this; } public JobTimeoutHelper setMaxCount(int maxCount){ this.maxCount = maxCount; return this; } public static void main(String[] args) { final Date today = new Date(); final Date tomorrow = DateUtils.addDays(today, +1); final Date yestoday = DateUtils.addDays(today, -1); JobTimeoutHelper.create().setIntervalCount(2).setMaxCount(3) .splitTime(yestoday, tomorrow,"JobTimeoutHelper", new TimeSplitHandler() { @Override public void deal(Date start, Date end) throws Exception { throw new MySQLNonTransientConnectionException(); } }); } }
這是一個任務超時幫助類,原來是經過遞歸的方式,不斷將時間拆小,這樣在龐大的數據面前也能夠淡定的run起來。只須要多花點時間而已。同時,也能夠配合多線程處理,讓程序加速奔跑起來。idea
舒適提示:要根據實際需求,記得要設置多少等份,和最大層級哦。線程