如何優化大數據量的方法

隨着項目上線,業務數據會愈來愈多。這個時候,不少開發時適用的方法、任務,在龐大數據量面前就會變得很不堪,常常會出現超時,慢查詢,異常等等問題。數據庫

因此,通常在開發階段,咱們怎麼能避免這些問題呢?一切皆有套路。緩存

通常處理套路:
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

舒適提示:要根據實際需求,記得要設置多少等份,和最大層級哦。線程

相關文章
相關標籤/搜索