由於工作中需要對大量數據進行快速校驗,試驗採用讀入記憶體List實體採用lamdba查找來實現。 實際需求:實際讀入記憶體數據 50W條記錄主集數據,還包含約20個子集,子集最大記錄數300W條記錄。讀入記憶體,校驗出結果5分鐘之內完成。 測試數據讀入記憶體後占用約2-3G記憶體。這裡測試了多線程讀取數據,但 ...
由於工作中需要對大量數據進行快速校驗,試驗採用讀入記憶體List實體採用lamdba查找來實現。 實際需求:實際讀入記憶體數據 50W條記錄主集數據,還包含約20個子集,子集最大記錄數300W條記錄。讀入記憶體,校驗出結果5分鐘之內完成。 測試數據讀入記憶體後占用約2-3G記憶體。這裡測試了多線程讀取數據,但提速效果並不明顯。SQLServer有自己的SQL執行排隊機制(讀入數據過程遇到一個小插曲,讀入速度慢,占用記憶體大,無意中發現是把記錄照片流也讀入了記憶體。實際處理數據過程並不需要照片信息。去掉後速度提升很大,占用記憶體也縮小很多,以後遇到類似操作應提前排除這類情況了) 數據校驗腳本由另一個同事寫的,大約有500個校驗,實體欄位合法性校驗,及主集子集關聯檢驗。開始拿到腳本丟進去測試,結果半個小時也沒反應。果斷結束進程。然後就是痛苦的優化過程,曾經懷疑這樣的方式行不通。差不多用了兩周時間,達到5000個主集信息10秒以內完成。50W數據也在3-5分鐘完成。最後完成100個併發測試。校驗結果正常返回。一切OK現已正常上線使用。 以下是在本次數據校驗實現過程中總結出來應註意的一些地方。
1、由原來資料庫校驗改為記憶體校驗,記憶體速度更快,資料庫校驗還會帶來併發等待,死鎖等問題。 2、載入數據可以採用多線程載入 3、主鍵使用整形加快查詢速度 這一點特別重要,速度提升上千倍。 4、採用lamdba表達式查找數據 用聯合查詢代替for迴圈 5、根據數據量的大小採用分別採取線性查找或二分查找提高查詢速度 6、共用數據只取一次,在整個校驗中全局使用。 併發測試 時發現 靜態類中的靜態屬性不是安全的 因為靜態類在記憶體中只有一份 去掉static 後多線程測試正常 以下為測試數據,及相關說明,可以直接忽略。感興趣的的可以看看。
1、7萬條記錄 A01.FindAll(x => !x.PersonStatus.In("01", "02", "03", "04")) 迴圈查找,共載入15298人,耗時:0.019519秒. A01.FindAll(x => !(x.PersonStatus == "01" || x.PersonStatus == "02" || x.PersonStatus == "03" || x.PersonStatus == "04")) 迴圈查找,共載入15298人,耗時:0.0284169秒. 2、3.3萬條記錄 x.CodeID == "ZB01"的有3300條記錄 Codes.FindAll(x => x.CodeID == "ZB01" && (x.CodeItemName == "市轄區" || x.CodeItemName == "縣")) 迴圈查找,共載入287人,耗時:0.0139286秒. Codes.FindAll(x => x.CodeID == "ZB01" && (x.CodeItemName.In("市轄區", "縣"))) 迴圈查找,共載入287人,耗時:0.0230568秒. 3、4000條記錄 codeIds有3300條記錄 personTableList.A01.FindAll(x => !x.A0114.In(codeIds)); A01 4000條記錄 迴圈查找,共載入0人,耗時:0.1066983秒. A01 7萬條記錄 迴圈查找,共載入0人,耗時:1.7386399秒. foreach (var A01 in personTableList.A01) { if (!codes.Exists(x => x.CodeItemID == A01.A0114)) { persons.Add(A01); } } 上面形式代碼,兩個列表都是7W條記錄時 迴圈查找,共載入75601人,耗時:55.4800723秒. 迴圈查找,共載入75601人,耗時:107.4412256秒. 3、 A01.FindAll(x => x.W0111G == "") 迴圈查找,共載入183人,耗時:0.0039961秒. A01.FindAll(x => x.W0111G.IsSame("")) 迴圈查找,共載入183人,耗時:0.0307353秒. A01.FindAll(x => ids2.IndexOf(x.PersonID)) 最快 A01.FindAll(x => x.PersonID.In(personIds)) 第二 A01.FindAll(x => ids2.Contains(x.PersonID)) 第二 A01.FindAll(x => ids2.Exists(p=>p == x.PersonID)) 最慢 聯合查詢 速度快 var query = (from A14 in DataList.A14 join A01 in DataList.A01 on A14.ID equals A01.ID select new { A14.ID, A14.A1407, A01.A0141 }).ToList(); personIds = query.FindAll(x => x.A0141 > x.A1407) 非常重要 主鍵欄位 整形欄位比字元串快上百倍 線性查找:Contains,Find,IndexOf都是線性查找。 二分查找:BinarySearch,因為二分查找必須是對有序數組才有效,所以查找前要調用List的Sort方法。 結論:如果List項的個數比較小,用線性查找要略快於二分查找,項的個數越多二分演算法優勢越明顯。可根據實際情況選用適合的查找方式。 測試數據2條 耗時:0.0186627秒. 二分耗時:0.0356611秒.