我負責運維的機票差旅分析報告項目, 分析報告所需的數據(訂單數據和基礎維度數據)是從業務庫抽取過來的。 其中,有一個用戶賬戶數據的同步程序, 今天查看線上日志,發現同步程序出現了異常:
執行ExecuteSqlCommand方法捕獲到System.Data.SqlClient.SqlException異常:違反了 PRIMARY KEY 約束“PK_BASEUSERACCOUNT”。不能在對象“dbo.BaseUserAccount”中插入重復鍵。重復鍵值為 (105487)。 違反了 PRIMARY KEY 約束“PK_BASEUSERACCOUNT”。不能在對象“dbo.BaseUserAccount”中插入重復鍵。重復鍵值為 (105488)。 語句已終止。 語句已終止。,SQL: insert BaseUserAccount(AccountId,AccountName,LoginName,EntId,EntName,DeptId,DeptName,CreateTime) values(74188,'薛彥','薛彥',49261,'太極計算機股份有限公司-智慧城市SBU部門一',49265,'銷售部','2016/1/19 16:11:23');insert BaseUserAccount(AccountId,AccountName,LoginName,EntId,EntName,DeptId,DeptName,CreateTime) values(74205,'徐琳','徐琳',49261,'太極計算機股份有限公司-智慧城市SBU部門一',49265,'銷售部','2016/1/19 16:11
程序底層是用EF實現的,賬戶同步的邏輯是把數據從數據源讀取過來放到一個List集合裡,然後在本地系統持久化時,先清空表,再將List的數據轉換後分批插入。 通過分析,是從數據源拿的數據裡有重復的數據,導致這邊插入時出現主鍵沖突。
數據源系統的數據存儲比較亂,我們改變不了。只能在我們這邊做文章了。 於是,決定的改進方案是:根據AccountId對集合數據去重。
我跟開發小組的一個同學說了一下,並叮囑,從數據源獲取到的記錄有6萬多條,注意優化一下去重算法。如果按常規的去重,估計要耗時5分鐘,期望優化後能控制在半分鐘內。
第二天,這個小同學交活了。 6萬條記錄的List集合,算法耗時平均不超過15毫秒。 贊一個!
他的實現方案是,利用List的Distinct方法,然後重寫了實體類的Equals方法。如下上代碼:
namespace EntOlap.ETL.EF { public partial class BaseUserAccount // 由於是EF,這裡新建一個partial類 { public override bool Equals(object obj) { BaseUserAccount bua = obj as BaseUserAccount; if (bua == null) { return false; } else { return this.AccountId == bua.AccountId; } } public override int GetHashCode() { return AccountId.GetHashCode(); } } }