標籤:
老李分享:大資料效能調優案例1、“空間換時間”以及“記憶體中處理資料”
比如user_id.csv檔案中有20萬個不同的user_id,根據user_id去查其對應的使用者最近發表的一篇文章,取出post_id,post_title、post_time和user_id(post表中查,post表中有一列是user_id,表示文章所屬者),而貼文數目有大概兩百萬,那麼如何處理呢?
我的解決方案是:
A. 先將post表post_id,post_title、post_time和user_id這四列匯出到posts.csv檔案中,然後利用一個CSV讀取組件將posts.csv檔案中的記錄讀取到csvRecords中
B. 然後利用“空間換時間的思想”,先將user_id.csv中的user_id讀取到userIdList的List對象中,然後再將userIdList轉為字典:
var userIdDict = userIdList.Distinct().ToDictionary(c => c, c => 1);
C. 最後比對userIdDict和csvRecords得到結果:
var resultRecords = csvRecords.Where(c => postDict.ContainsKey(c.UserId)).ToList(); // 這裡ContainsKey的查詢時間複雜度為O(1)
2、JOIN最佳化查詢效能
一個頁面查詢效率非常低(一分多鐘都沒有結果),查詢過程後台執行了3條SQL,其中2條SQL的執行時間都在39秒左右(2條SQL類似),造成資料庫連接逾時。
後台資料庫查詢用的是EF架構,而EF架構使用不當的話很容易導致糟糕的查詢效能。
簡單地類比下(資料庫表名已調整,記錄數也有所改動,不影響結果):
用2張表:一張表為賬戶表比如account,記錄數大概為3000條。另外一張表比如為文章表post,記錄數大概為190萬。
然後幕後處理過程大概是:先根據查詢條件取得賬戶表的account_id的列表accountIds,然後再根據account_id列表去找post記錄(post表有一個欄位為account_id),大概這樣:
var posts= db.Posts.Where(m).Where(c => accountIds.Contains(c.AccountId));
不需要過於關注這行代碼,我用工具監測到這行代碼對應的SQL為:
SELECT * from post
WHERE
((20 = account_id) OR (21 = account_id)) OR ...
ORDER BY created_at DESC
LIMIT 0, 15;
上面的OR條件大概有2000多個。EXPLAIN結果顯示ROWS值達到134萬多,也沒有使用索引。
因為多了ORDER BY子句造成效率低,但是不能為了最佳化而省掉它,因為業務要求第一頁顯示最近的15篇文章。
用JOIN查詢,自己手工拼了一條SQL,發現幾乎瞬間出結果,SQL大概如下:
SELECT * FROM
posts AS A
JOIN
accounts AS B
ON A.account_id = B.id
WHERE A.category = 1 # 文章的分類
ORDER BY A.created_at DESC
LIMIT 0, 15;
按照這個方法,捨棄EF,改用拼SQL的方法重寫代碼了。速度改進不少,原來需要近2分鐘才能顯示查詢結果,現在只需要3-4秒。
這個情境用JOIN能提高查詢效率,是因為一張表的記錄數只有3000條左右,而另外一張有幾百萬的資料。如果兩張表的資料都有幾百萬,那用JOIN未必能提高查詢效率
3、商務邏輯代碼層面最佳化
理解透徹商務邏輯,去除冗餘商務邏輯代碼
原文連結;http://www.cnblogs.com/laoli0201
老李分享:大資料效能調優案例