使用Java程序一次分段讀取所有數據(如海量數據)並計數處理


前段時間遇到一個問題,很簡單就是定時任務刪除數據庫中三個月前的數據;無非就是delete...from...where;當時的需求要考慮這幾個問題:

1.效率

2.一次讀取全部

3.保留部分數據

先說一下當時的需求,刪除三個月前的動態(團隊動態),但有些團隊的動態本身就很少,刪除了影響前台數據量,所以只刪除三個月內動態>200條的數據;

其實完全可以一個簡單的delete  from,count計數,但這對磁盤IO消耗很大;所以要在內存中處理;如何讀取數據,計數是主要問題;

下面是當時實現代碼

//定時刪除團隊動態
public class AutoDelTeamDynamic {

	protected final static Log logger = LogFactory.getLog(AutoDelTeamDynamic.class);
	
	public void executeInternal() {
		logger.warn(" autoDelTeamDynamic start! ");
		Date d = new Date();//當前時間
		Date startDate = DateUtil.getDateInDayAgo(d, -90);
		Date delDate = DateUtil.dateUtil2date(startDate, "yyyy-MM-dd");//三個月前
		//三個月團隊內動態數量大於200刪除
		Long id = 0l;
		String dynamics = "select id,team_id,create_time from g_team_dynamic where id > ? order by team_id asc,id desc limit 10000";
		while(true){
			List<Map<String, Object>> result = Db.executeQuery(dynamics, new Object[]{id},false);
			if(result == null || result.size() < 10000){
				break;
			}
			Map<Long,Integer> map = new HashMap<Long, Integer>();
			StringBuffer sb = new StringBuffer();
			for(Map<String, Object> numMap : result){
				id = (Long)numMap.get("id");
				Long team_id = (Long)numMap.get("team_id");
				Date create_time = (Date)numMap.get("create_time");
				Date date = DateUtil.dateUtil2date(create_time, "yyyy-MM-dd");
				if(DateUtil.compareTwoDate(date, delDate) == 1){
					if(map.containsKey(team_id)){
						map.put(team_id, map.get(team_id) + 1);
						if(map.get(team_id) > 200){
							sb.append(id).append(",");
						}
					}else{
						map.put(team_id, 1);
					}
				}
			}
			if(sb.length() > 0){
				sb.deleteCharAt(sb.length()-1);
				delDynamic(sb.toString());
			}
			id--;
		}
		logger.warn(" autoDelTeamDynamic end! ");
	}
	
	private void delDynamic(String ids){
		String delsql = " DELETE FROM g_team_dynamic WHERE id in ("+ids+")";
		int a = Db.executeUpdate(delsql,null, false);
		if(a <= 0){
			logger.error("刪除每日任務記錄失敗!"+delsql);
		}
	}
}

以上代碼是工程中的,只是一個思路問題;SQL語句是分段讀取數據的,如何讓分段讀取能夠讀取到數據庫中全部數據,這里用到了while(true),每次讀取10000條,即只要數據庫中數據還多於一萬就一直向下執行,直到數據少於10000時結束;還有個問題就是分段讀取數據的銜接,注意Long id=0,及SQL語句中的where條件,主鍵id之后被數據中讀取數據重新賦值,一次循環執行SQL結束,id--,這樣就可以將兩次Limit的數據銜接上(id主鍵自增),如此執行,就可以一次讀取到數據庫中所有數據;

下面就是計數問題,在這里是使用Map計數的,每當發現一個team_id,判斷Map中是否包含,不包含創建,計數1;包含則在原來個數上加一,如此計數,當team_id對應數據大於200,直接將數據庫中記錄id放入可刪除字符串中;

最后就是根據主鍵刪除記錄,如此做是效率最高的刪除操作,where條件放入in條件,一次傳入所有需要刪除記錄的ID;

這樣就可以實現需求;海量數據處理確實很難模擬,不在互聯網公司很難接觸到,一個刪除操作就要如此麻煩,但我們都應該知道,內存可以擴展,但IO處理對效率的影響會更大;




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM