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

Odpovedet emailem