2016-08-17 115 views
-2

我需要解析一個來自先前查詢的巨大ResultSet,我想出了一些東西,但它太慢了。ResultSet解析器太慢

public LinkedList<CountryFirstData> sortCountryFirst() throws SQLException { 

    long parsingStart = System.nanoTime(); 


    LinkedList<CountryFirstData> list = new LinkedList<CountryFirstData>(); 

    String serie; 
    String unit; 
    String country; 
    BigDecimal value; 
    int year; 
    int index; 

    while (rs.next()) { 

     serie = rs.getString(1); // rs is the previously built resultSet 
     unit = rs.getString(2); 
     country = rs.getString(3); 
     value = rs.getBigDecimal(4); 
     year = rs.getInt(5); 
     if ((index = list.indexOf(new CountryFirstData(country, serie, unit))) != -1) { 

      list.get(index).getDuo().add(new YearValueDuo(year, value)); 

     } 
     else { 

      CountryFirstData data = new CountryFirstData(country, serie, unit); 
      data.getDuo().add(new YearValueDuo(year, value)); 
      list.add(data); 

     } 



    } 
    long parsingEnd = System.nanoTime(); 

    Collections.sort(list); 

    long sortEnd = System.nanoTime(); 


    System.out.println("Parsing Time = " + ((parsingEnd - parsingStart)/1000000000)); // gives 112s 
    System.out.println("Sorting Time = " + ((sortEnd - parsingEnd)/1000000000)); // gives 0s 


    return list; 

} 

我會盡量解釋一下代碼:

ResultSet中列包含5個不同的值。第一個要考慮的三人組成爲country,serieunit。當我第一次得到這樣一個三人組(else案例)時,我需要創建一個新的CountryFirstData,並將resultSet行中的剩餘年份/值添加到創建的對象中的YearValueDuo列表字段。

當三人countryserieunitlistif情況下)已經存在,我需要找回它,兩人年/值添加到其YearValueDuo名單。

所以,基本上,resultSet rs是4000行,整個解析(排除排序)需要2分鐘。我覺得這隻有4k線太多了。排序仍然很快(不到一秒)。

我選擇LinkedList代替CountryFirstData而不是ArrayList,因爲後來我按順序在文件中寫入了整個列表(這非常快)。

你們可以建議我一些改進嗎?

+2

你爲每一行執行''list.indexOf(new CountryFirstData(country,serie,unit))''''。根據「CountryFirstData.equals」的複雜程度,當「list」有3999個條目時,這可能需要很長時間。嘗試測量每個行的「indexOf」方法的時間。 – f1sh

+0

@ f1sh Will do,ty。我還沒有找到更好的方法來測試列表中是否存在指定的'CountryFirstData'。 – Fitz

+0

比較(在列表中)一個對象實例,添加另一個對象似乎很難看。 –

回答

1

一個List,並且實際上是一個Set(no double),然後進行排序。並返回實現類,強制進一步使用該類型,防止實現更改。

public Set<CountryFirstData> sortCountryFirst() throws SQLException { 

    long parsingStart = System.nanoTime(); 

    SortedMap<CountryFirstData, CountryFirstData> identityMap = new TreeMap<>(); 
    //  Comparator.comparing(CountryFirstData::getCountry) 
    //   .thenComparing(CountryFirstData::getSerie)) 
    //   .thenComparing(CountryFirstData::getUnit)); 

    while (rs.next()) { 

     String serie = rs.getString(1); // rs is the previously built resultSet 
     String unit = rs.getString(2); 
     Stribg country = rs.getString(3); 
     BigDecimal value = rs.getBigDecimal(4); 
     int year = rs.getInt(5); 
     CountryFirstData data = new CountryFirstData(country, serie, unit)); 
     CountryFirstData oldData = identityMap.putIfAbsent(data, data); 
     if (oldData != null) { 
      data = oldData; 
     } 
     data.getDuo().add(new YearValueDuo(year, value)); 
    } 
    long parsingEnd = System.nanoTime(); 

    System.out.println("Parsing Time = " + ((parsingEnd - parsingStart)/1_000_000_000L)); 

    return (SortedSet<CountryFi‌​rstData>) identityMap.keySet()‌​; 
} 

這依賴於已有的上等號比較

這裏的訣竅是 - 雖然你只需要一個Set - ,需要一個標識映射來獲取舊的等值'(Set.add只返回一個布爾值)。


由於這仍是緩慢:

確保ResultSet中已經被SQL ORDER BY serie, unit, country排序。 (如果已經排序,將在之前的解解釋緩慢:樹圖,變成一個線性表。)

public List<CountryFirstData> sortCountryFirst() throws SQLException { 

    long parsingStart = System.nanoTime(); 

    List<CountryFirstData> identityMap = new ArrayList<>(); 
    CountryFirstData oldData = null; 
    while (rs.next()) { 
     String serie = rs.getString(1); // rs is the previously built resultSet 
     String unit = rs.getString(2); 
     Stribg country = rs.getString(3); 
     BigDecimal value = rs.getBigDecimal(4); 
     int year = rs.getInt(5); 
     CountryFirstData data = new CountryFirstData(country, serie, unit)); 
     if (oldData == null || data.compareTo(oldData) != 0) { 
      oldData = data; 
      list.add(data); 
     } 
     oldData.getDuo().add(new YearValueDuo(year, value)); 
    } 
    long parsingEnd = System.nanoTime(); 

    System.out.println("Parsing Time = " + ((parsingEnd - parsingStart)/1_000_000_000L)); 

    return list; 
} 

這使得辛勤工作到數據庫。什麼是最快的,可以利用指數。

+0

我想你的意思是'返回list.keySet();'實際'返回identityMap.keySet();'? Ty,我現在就試試。 – Fitz

+0

贏了我5秒。總比沒有好,謝謝!只需要說:'返回(SortedSet )identityMap.keySet();' – Fitz

+0

我已經添加了一個非常快速的解決方案,但它需要更改SQL。 –