2016-08-17 116 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。 –