Oto Buchta wrote:
On Sunday 23 of October 2005 02:46, Petr Michálek wrote:
Dobrý den,
vase diskuze me primela k malemu testu. Mym cilem bylo zmerit dobu
natazeni natazeni vetsiho poctu radku pres JDBC.
Pred samotnym nahranim radku jsem presel na posledni zaznam a zpet.
Vysledek naznacuje, ze data jsou do klientske JVM natazeny jiz ve fazi
vykonani SQL dotazu, nicmene vyuziti pameti nedosahuje kritickych hodnot.
No to jsou IMHO VELMI kriticka data pro vyuziti pameti. Data jsou v JVM
zdvojena. Navic v okamziku, kdy neni nutne nahrat vse do pameti, je
evidentni, je toto opravdu mrhani prostredky. Co kdyby slo o Webovy server?
Paralelni pristup tisici klientu znamena tisic paralelnich resultsetu, takze
2tisicekrat preneseni dat z databaze na server. Pak uz je opravdu pouziti DB
uplne zbytecna vec, protoze vetsinu rezie sezerou IO operace, obzvlaste pak
pri pouze stovkove siti ;-)
Myslim, ze za neprimerene vyuziti pameti muze JDBC Driver, ktery
obsahuje nasledujici kod:
protected Object internalGetObject(int columnIndex, Field field)
throws SQLException
{
switch (getSQLType(columnIndex))
{
case Types.BIT:
// Also Types.BOOLEAN in JDBC3
return getBoolean(columnIndex) ? Boolean.TRUE : Boolean.FALSE;
case Types.TINYINT:
case Types.SMALLINT:
case Types.INTEGER:
return new Integer(getInt(columnIndex));
case Types.BIGINT:
return new Long(getLong(columnIndex));
case Types.NUMERIC:
case Types.DECIMAL:
return getBigDecimal
(columnIndex, (field.getMod() == -1) ? -1 :
((field.getMod() - 4) & 0xffff));
case Types.REAL:
return new Float(getFloat(columnIndex));
case Types.FLOAT:
case Types.DOUBLE:
return new Double(getDouble(columnIndex));
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
return getString(columnIndex);
case Types.DATE:
return getDate(columnIndex);
...
public int getInt(int columnIndex) throws SQLException
{
return toInt( getFixedString(columnIndex) );
}
Dale bych podotknul, ze drtivou vetsinu casu executeQuery("...") travi
server vykonavanim dotazu.
Ano, obzvlaste ten prvni pripad ukazuje, ze vysledek o 20MB dat nad peti
tabulkami nebyl nejtrivialnejsi. Hodne bych sazel na to, ze DB nejela podle
plne indexace, ale hodne se muselo cist zbytecne a skakat. Navic hlavicka na
disku se pak asi hodne natrepala pri neustalem preskakovani mezi sektory.. No
a v druhem pripade se muselo 70MB nacist z disku do pameti a prenest po
stovkove siti z jednoho pocitace na druhy ;-)
I kdyz me uvedeny sql dotaz me pali ze vseho nejmin, tak se nad tim
zamyslim. Jinak dodam, ze pri prechodu na postgresql 8.1 jsem musel
nektere dotazy prepsat nebo si pohrat s indexy, aby byly rychlejsi nez
na 8.0. Samozrejme to ale nekazi celkovy dojem z 8.1, která se mi jevi v
porovnani s predchozi verzi rychla jako blesk.
Jeste doplnim, ze stroje, na kterych bezely uvedene testy maji opravdu
dostatek volne pameti a veskera data tak byla zrejme v cache.
Zkuste polozit tyto dotazy primo z klienta a vypis hnat do /dev/null, aby
zbytecne nezatezoval klienta a zmerte casovy rozdil. JIste bude, ale nerekl
bych, ze bude v radu.
TEST 1:
Dotaz do 5 tabulek, ktery vratil 83738 radku a 12 sloupcu.
Vyuziti pameti Cas(ms) Popis cinosti
2059808 - pred dotazem
22743400 12301 vykonani dotazu - execute(query)
22743400 0 Scrollovani na konec resultset.last()
resultset.getRow() vraci 83738 radku.
45122128 5901 resultset.getFirst()
Zkopirovani vysledku do ArrayList<Object[]>
Test 2:
Dotaz do 1 tabulky, ktery vratil 312577 radku a 12 sloupcu.
Vyuziti pameti Cas(ms) Popis cinosti
2002384 - pred dotazem
74867872 9073 vykonani dotazu - execute(query)
74867872 2 Scrollovani na konec resultset.last()
resultset.getRow() vraci 312577 radku.
155728968 23849 resultset.getFirst()
Zkopirovani vysledku do ArrayList<Object[]>
/usr/local/pgsql/bin/psql "select * from tabulka">/dev/null
zvladne na serveru asi za 7 vterin.
vykonani tohoto dotazu na klientovi trva asi 10 vterin, ztoho server
pracuje asi 3 vteriny a zbytek doby pripada na klienta.
Petr Michalek