[JAVA] Grote resultSet -> HashMap

Pagina: 1
Acties:

  • Banaan
  • Registratie: Maart 2000
  • Laatst online: 21-08 13:12
Ik moet voor een applicatie een grote hoeveelheid gegevens uit de database lezen en deze gaan opslaan in een Hashmap. Dit neemt echt behoorlijk veel tijd in beslag en ik moet dit dus gaan optimaliseren. Als ik echter met een profiler ga kijken waar ik zou gaan moeten optimaliseren zie ik de volgende resultaten (kan hier nu niet oploaden, vandaar dat het geen plaatje is)

- 34.4% - 19763 ms - 70129 inv. java.sql.ResultSet.next
- 20.2% - 11644 ms - 140256 inv. java.sql.ResultSet.getInt
- 15.8% - 9093 ms - 1 inv. java.sql.PreparedStatement.executeQuery
- 11.0% - 6307 ms - 70128 inv. java.sql.ResultSet.getDouble
- 10.1% - 5784 ms - 70128 inv. java.sql.ResultSet.getDate
- 4.7% - 2720 ms - 1 inv. com.xxxxx.dataaccess.ConnectionPool.getConnection

De code is als volgt:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
HashMap prices  = new HashMap();
Connection con  = ConnectionPool.getConnection();

query = "SELECT day, hour, sourceID, price FROM HourlyPrices" 
+"ORDER BY sourceID, day, hour";

preparedStatement = con.prepareStatement(query);
resultSet        = preparedStatement.executeQuery();

while (resultSet.next()) {
  Date day      = new Date(resultSet.getDate(1).getTime());
  int hour      = resultSet.getInt(2);
  int sourceID  = resultSet.getInt(3);
  double price  = resultSet.getDouble(4);

  DayTimeKey key  = new DayTimeKey(day, hour, sourceID);

  prices.put(key, new Double(price));
}


Ik heb al geprobeerd om de HashMap een grote initiele waarde mee te geven, maar dat had geen merkbaar effect. Ik heb de fetch size van de ResultSet vergroot, en dat levert ongeveer een halve minuut op, maar dan duurt het alsnog 4,5 minuut. En aangezien dit voor twee tabellen gebeurd, is dat gewoon te lang. Het gaat hier trouwens om tabellen met ongeveer 70.000 records..

Heeft iemand nog andere suggesties?

Verwijderd

Ik heb bij IBM (na even te googlen) de volgende link gevonden: JDBC Performance Tips. Ik denk dat met name het gedeelte over block fetch (Use Blocked fetch) interessant is om naar te kijken, gezien de grootte van de result sets die je terugkrijgt.

Hoop dat je er iets aan hebt!

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 30-07 16:33
Laat die hele ORDER BY maar weg, want die order ben je in je HashMap toch weer kwijt.

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Wat ik me bij zoiets dan altijd afvraag is wat het nut van je database is (of juist van de hashtable) als je alle data eruit gaat lopen halen en vervolgens in je geheugen stopt. Dan gebruik je het, imho, niet heel handig.

Anyway, als dat de ergste methoden zijn, dan zit de tijd voornamelijk in het verschuiven binnen het recordset (wat dan ook 70129 keer gedaan wordt) en het ophalen van de de specifieke elementen van die records (de 140256 keer de getInt en de 70128 keer getDouble en getDate).
De put en new DateTimeKey merk je blijkbaar niet zoveel van, aangezien die ook 70128 keer worden uitgevoerd...

Dus je moet het iig in het transport deel (database -> jouw applicatie) zoeken lijkt me.

2 seconde om een pooled connection te krijgen is trouwens ook wel heel erg lang, hoe zwaar wordt die database belast?

[ Voor 8% gewijzigd door ACM op 27-08-2003 14:54 ]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:56
Als ik het goed begrijp, wordt 90% van de tijd besteedt binnen de java.sql methoden. Het heeft dus maar weinig zin om de code die daar los van staat (zoals die hash map) te optimaliseren, aangezien dat in totaal maar 10% van de tijd is (en je dus waarschijnlijk maximaal zo'n 5% winst kan boeken.

Aangezien je java.sql methoden zelf waarschijnlijk niet kunt optimaliseren (tenzij je hun implementatie via configuratieopties kunt aanpassen), is de enige manier om de prestaties te verbeteren het voorkomen van die aanroepen. Uitzondering op de regel is de executeQuery call, waarvan de performance wel voor het grootste deel door je invoer wordt bepaald; door die query te optimaliseren kun je van de 15% die die methode waard is een deel afhalen. Misschien kun je de getConnection call ook optimaliseren door een andere soort socket te gebruiken (dan TCP, nu, waarschijnlijk).

Voor de overige methoden geldt dat ze in principe wel efficient zijn, maar gewoon heel vaak aangeroepen worden. Weet je zeker dat je alle resultaten nodig hebt; kun je niet al een deel van de resultaten met je query wegfilteren? Als je je result set kunt verkleinen, dan verklein je ook automatisch het aantal calls op de methoden next, getInt, getDouble en getDate en daar valt wel het een en ander mee te winnen. De kans is ook groot dat het executen van je query daar efficienter van wordt, omdat de database server dan minder query resultaten lokaal hoeft te kopiëren (mocht dat gebeuren).

Verwijderd

Wat als je ipv de specifieke getInt/Date/Double gewoon getString() gebruikt, en die in een object zet waarin je pas wanneer het echt nodig is, de conversie naar int/date/double etc uitvoert?
Oftewel, hoe verhoudt zich de tijd die getString(0 kost t.o.v. getDate/Int/Double?
Als je jdbc-driver de werkelijke data namelijk als strings binnenkrijgt, scheelt dat de vele conversies tijdens het inlezen. Just a wild guess, maar valt eenvoudig te proberen of het wat uitmaakt. Feitelijk verschuif je de tijd die de conversies kosten dan gewoon, maar de vraag is of alle int/date/doubles wel echt nodig zijn; zo niet, dan komt van uitstel (vaak) afstel en dus totaal een betere performance.

Verder kun je de locale variabelen die binnen de while worden gebruikt, beter erbuiten declareren, dat scheelt technisch gezien toch weer een paar honderdduizend declaraties (hoewel de huidige java-compilers er meestal wel mooie optimized code van weten te bakken zodat de gevolgen beperkt blijven).

PS Wat voor database en systeem draai je eigenlijk mee? Inlezen van honderduizenden eenvoudige records is hier toch echt binnen een paar seconden gedaan...

  • demonite
  • Registratie: April 2000
  • Laatst online: 29-05 08:55

demonite

the way is up

4.5 min voor 70.000 records. Dat is te lang, optimized of niet... Ik zou idd wel eens willen weten op wat voor machine dat spul draait.

Bijna 3 seconden om een connectie uit een connectionpool te verkrijgen. Werk je nog met een 28k8 modem ofzo ? :)
Pagina: 1