簡體   English   中英

在性能方面實現功能的最佳實現

[英]Optimal implementation of function in terms of performance

我有一個項目列表和一個地圖,該地圖存儲有關產品及其項目數據的信息。 數據庫中大約有15萬個商品,大約有20萬個產品(每個產品都有大約1000至2000個商品映射到該商品)。

我需要一個功能來統計每個項目中出現的產品數量。這是我已經實現的功能:

public Map<Integer, Integer> getProductsNumberForItem(List<Item> itemsList,
        Map<Integer, Map<Item, Integer>> itemsAmount) {
    Map<Integer, Integer> result = new HashMap<>();
    for (Item i : itemsList) {
        int count = 0;
        for (Map<Item, Integer> entry : itemsAmount.values()) {
            if (entry.containsKey(i)) {
                count++;
            }
        }
        result.put(i.getID(), count);
    }
    return result;
}

它在包含少量數據的測試數據庫上可以正常工作,但是當我在真實數據上運行它時,會花費太多時間(例如:它已經運行了一個小時,但尚未完成)。 從邏輯的角度來看,很明顯,我基本上執行了太多操作,但是不確定如何進行優化。

任何建議表示贊賞。

您有兩種方法:

  • 最有效:在數據庫中執行的查詢中進行計算。
    使用count()聚合和group by子句,您應該獲得更好的結果,因為整個處理將由經過設計/優化的DBMS執行。

  • 效率較低,但您可以嘗試一下:像現在一樣檢索數據並使用多線程。
    使用Java 8 parallelStream() ,您可能會獲得可接受的結果,而無需麻煩自己處理同步。

最好的選擇是將此計算委托給db,從而避免了將所有數據傳輸到應用程序服務器的需要。

如果這不是一個選擇,那么可以肯定的是您可以改進當前的算法。 現在,對於列表中的每個項目,您都在瀏覽所有產品。 那是指數成本。

您可以做到這一點(使用流,因為我認為響應更容易遵循,並且還可以添加一些改進;但是沒有它們也可以實現):

Stream<Item> productsItemsStream = itemsAmount.values().stream().flatMap(p -> p.keySet().stream());
Map<Item,Long> countByItemFound = productsItemsStream.collect(Collectors.groupingBy(Function.identity(), Collectors.counting());
Map<Integer, Integer> result = itemsList.stream().collect(Collectors.toMap(Item::getID, i -> countByItemFound.getOrDefault(i.getID(), 0L).intValue()));

通過這種方法,您將對產品進行一次完整的傳遞。 然后另一個傳遞到項目列表。 那是線性成本。

對於流,您可以嘗試啟用並行性(將並行流添加到我的解決方案中),但是並不能完全保證它具有顯着的性能提升。 取決於幾個因素。 我將等着看建議的解決方案的性能,並在需要時在有無並行流的情況下分析性能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM