Avatar billede jespersahner Nybegynder
18. oktober 2004 - 16:53 Der er 11 kommentarer og
1 løsning

Sekventiel gennemlæsning af data - tekstfil eller database?

Jeg har et helt overordnet spm. vedr. sekventiel gennemlæsning af data, som kan være gemt i enten en tekstfil eller en relationel database.

Spørgsmålet går på, hvilken metode der er hurtigst (tekstfil eller databse), og hvilken teknik man i øvrigt bør benytte ved sekventiel indlæsning fra tekstfil (der er noget med random access, buffere mv., som jeg ikke har forstand på), som skal behandles og derefter gemmes igen i en ny tekstfil eller en ny tabel i databasen.

Mht. vurdering af database-løsningen forestiller jeg mig, at databasen i første omgang er placeret på egen harddisk og man har en hurtig JDBC-driver til rådighed, så evt. ekstratid ved opkald til ekstern server ikke forstyrrer.

Jeg er godt klar over, at spørgsmålet er meget overordnet, men da der er tale om sekventiel gennemlæsning snarere end små queries, er jeg i tvivl om, hvilken vej man bør gå. Såfremt der er tale om joins af flere tabeller er jeg også godt klar over, at "tekstfil-metoden" kan blive meget grim eller nærmest umulig.

Min primære interesse er i første omgang at få afdækket, hvor hurtigt man (sekventielt) kan få indlæst en række informationer, behandlet dem og få dem gemt igen.
Avatar billede arne_v Ekspert
18. oktober 2004 - 16:56 #1
Ved sekventiel læsning & skrivning vil en tekst fil være hurtigere end alt andet.

Og stort set det eneste som betyder noget for performance er buffer størrelse.
Avatar billede arne_v Ekspert
18. oktober 2004 - 16:57 #2
Og hvis du skal bruge SQL capability (joins) så skal du vælge en database.
Avatar billede jespersahner Nybegynder
18. oktober 2004 - 17:30 #3
-> arne_v: Det regnede jeg også med, at tekstfilen ville være. Kan du sige noget mere (generelle betragtninger) omkring bufferstørrelse og access-metode? Ville man f.eks. have nogen glæde i forhold til hastighed ved at gemme i en binær fil med indbyggede skilletegn/delimiters snarere end en tekstfil?
Avatar billede _carsten Nybegynder
18. oktober 2004 - 17:30 #4
Umiddelbart - men er ikke sikker, og jeg har ikke tid til at lave testen før senere på aftenen, ville jeg tro at RandomAccessFile er hurtige at læse/skrive end en tekstfil, den kan jo læses både sekventielt og ikke sekventiel, men det må jo komme an på en prøve senere på dagen.

Ved ikke om Arne har gjort nogen forsøg med den (så var jeg måske fri for at teste) ??
Avatar billede arne_v Ekspert
18. oktober 2004 - 18:39 #5
Man ser markante hastigheds forøgelser ved større buffer op til vel
omkring en 100 KB, så er der ikke meget mere at hente.

Der er ikke nogen reel forskel på tekst og binære filer på Windows & Unix/Linux
(der er på andre platforme).

Du kan spare en lille bitte smule ved at undgådyr formatering (det er hurtigere at
udskrive et byte array direkte end at udskrive 10 objekter konkataneret).
Avatar billede arne_v Ekspert
18. oktober 2004 - 18:40 #6
Der burde ikke være hurtigere at læse 10 MB sekventielt fordi samme kode også
kunne læse filen random access.

Måske var det værd at kigge lidt på NIO.
Avatar billede arne_v Ekspert
18. oktober 2004 - 18:42 #7
Lidt kode at lege med:

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class ReadTest {
    final static String FILE_NAME = "C://readtest.dat";
    public static void main(String[] args) throws Exception {
        createFile();
        (new UnbufferedSmallReadTest()).doTest();
        (new UnbufferedSmallReadTest()).doTest();
        (new UnbufferedSmallReadTest()).doTest();
        (new UnbufferedLargeReadTest()).doTest();
        (new UnbufferedLargeReadTest()).doTest();
        (new UnbufferedLargeReadTest()).doTest();
        (new BufferedSmallReadTest()).doTest();
        (new BufferedSmallReadTest()).doTest();
        (new BufferedSmallReadTest()).doTest();
        (new BufferedLargeReadTest()).doTest();
        (new BufferedLargeReadTest()).doTest();
        (new BufferedLargeReadTest()).doTest();
        (new NioSmallReadTest()).doTest();
        (new NioSmallReadTest()).doTest();
        (new NioSmallReadTest()).doTest();
        (new NioLargeReadTest()).doTest();
        (new NioLargeReadTest()).doTest();
        (new NioLargeReadTest()).doTest();
    }
    private static void createFile() {
        try {
            OutputStream f = new FileOutputStream(FILE_NAME);
            for(int i = 0; i < 10000000; i++) {
                f.write((i % 256));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
abstract class GenericReadTest {
    GenericReadTest() {
    }
    void doTest() throws Exception {
        long t1 = System.currentTimeMillis();
        readAndCheck();
        long t2 = System.currentTimeMillis();
        System.out.println(getType() + " : " + (t2 - t1));
    }
    abstract void readAndCheck() throws Exception;
    abstract String getType();
}
abstract class UnbufferedReadTest extends GenericReadTest {
    void readAndCheck() throws Exception {
        try {
            InputStream f = new FileInputStream(ReadTest.FILE_NAME);
            byte[] b = new byte[getReadSize()];
            int n;
            int ix = 0;
            while((n = f.read(b)) >= 0) {
                for(int i = 0; i < n; i++) {
                    if(b[i] != (byte)(ix % 256)) {
                        throw new Exception("Bad data read - offset " + ix + " expected " + (byte)(ix % 256) + " found " + b[i]);
                    }
                    ix++;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    abstract int getReadSize();
}
abstract class BufferedReadTest extends GenericReadTest {
    void readAndCheck() throws Exception {
        try {
            BufferedInputStream f = new BufferedInputStream(new FileInputStream(ReadTest.FILE_NAME));
            byte[] b = new byte[getReadSize()];
            int n;
            int ix = 0;
            while((n = f.read(b)) >= 0) {
                for(int i = 0; i < n; i++) {
                    if(b[i] != (byte)(ix % 256)) {
                        throw new Exception("Bad data read - offset " + ix + " expected " + (byte)(ix % 256) + " found " + b[i]);
                    }
                    ix++;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    abstract int getReadSize();
}
abstract class NioReadTest extends GenericReadTest {
    void readAndCheck() throws Exception {
        try {
            FileChannel f2 = (new FileInputStream(ReadTest.FILE_NAME)).getChannel();
            ByteBuffer f = f2.map(FileChannel.MapMode.READ_ONLY, 0, 10000000);
            byte[] b = new byte[getReadSize()];
            int ix = 0;
            while(ix < 10000000) {
                f.get(b);
                for(int i = 0; i < b.length; i++) {
                    if(b[i] != (byte)(ix % 256)) {
                        throw new Exception("Bad data read - offset " + ix + " expected " + (byte)(ix % 256) + " found " + b[i]);
                    }
                    ix++;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    abstract int getReadSize();
}
class UnbufferedSmallReadTest extends UnbufferedReadTest {
    int getReadSize() {
        return 10;
    }
    String getType() {
        return "Unbuffered small reads";
    }
}
class UnbufferedLargeReadTest extends UnbufferedReadTest {
    int getReadSize() {
        return 1000000;
    }
    String getType() {
        return "Unbuffered large reads";
    }
}
class BufferedSmallReadTest extends BufferedReadTest {
    int getReadSize() {
        return 10;
    }
    String getType() {
        return "Buffered small reads";
    }
}
class BufferedLargeReadTest extends BufferedReadTest {
    int getReadSize() {
        return 1000000;
    }
    String getType() {
        return "Buffered large reads";
    }
}
class NioSmallReadTest extends NioReadTest {
    int getReadSize() {
        return 10;
    }
    String getType() {
        return "Nio small reads";
    }
}
class NioLargeReadTest extends NioReadTest {
    int getReadSize() {
        return 1000000;
    }
    String getType() {
        return "Nio large reads";
    }
}
Avatar billede arne_v Ekspert
18. oktober 2004 - 18:45 #8
Output hos mig:

Unbuffered small reads : 1765
Unbuffered small reads : 1781
Unbuffered small reads : 1750
Unbuffered large reads : 219
Unbuffered large reads : 172
Unbuffered large reads : 188
Buffered small reads : 343
Buffered small reads : 328
Buffered small reads : 344
Buffered large reads : 172
Buffered large reads : 172
Buffered large reads : 187
Nio small reads : 594
Nio small reads : 438
Nio small reads : 469
Nio large reads : 156
Nio large reads : 125
Nio large reads : 141
Avatar billede arne_v Ekspert
18. oktober 2004 - 19:12 #9
Jeg tilføjede lige RandomAccessFile. Som ventet ingen forskel.

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class ReadTest {
    final static String FILE_NAME = "C://readtest.dat";
    public static void main(String[] args) throws Exception {
        createFile();
        (new UnbufferedSmallReadTest()).doTest();
        (new UnbufferedSmallReadTest()).doTest();
        (new UnbufferedSmallReadTest()).doTest();
        (new UnbufferedLargeReadTest()).doTest();
        (new UnbufferedLargeReadTest()).doTest();
        (new UnbufferedLargeReadTest()).doTest();
        (new BufferedSmallReadTest()).doTest();
        (new BufferedSmallReadTest()).doTest();
        (new BufferedSmallReadTest()).doTest();
        (new BufferedLargeReadTest()).doTest();
        (new BufferedLargeReadTest()).doTest();
        (new BufferedLargeReadTest()).doTest();
        (new NioSmallReadTest()).doTest();
        (new NioSmallReadTest()).doTest();
        (new NioSmallReadTest()).doTest();
        (new NioLargeReadTest()).doTest();
        (new NioLargeReadTest()).doTest();
        (new NioLargeReadTest()).doTest();
        (new RandomAccessSmallReadTest()).doTest();
        (new RandomAccessSmallReadTest()).doTest();
        (new RandomAccessSmallReadTest()).doTest();
        (new RandomAccessLargeReadTest()).doTest();
        (new RandomAccessLargeReadTest()).doTest();
        (new RandomAccessLargeReadTest()).doTest();
    }
    private static void createFile() {
        try {
            OutputStream f = new FileOutputStream(FILE_NAME);
            for(int i = 0; i < 10000000; i++) {
                f.write((i % 256));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
abstract class GenericReadTest {
    GenericReadTest() {
    }
    void doTest() throws Exception {
        long t1 = System.currentTimeMillis();
        readAndCheck();
        long t2 = System.currentTimeMillis();
        System.out.println(getType() + " : " + (t2 - t1));
    }
    abstract void readAndCheck() throws Exception;
    abstract String getType();
}
abstract class UnbufferedReadTest extends GenericReadTest {
    void readAndCheck() throws Exception {
        try {
            InputStream f = new FileInputStream(ReadTest.FILE_NAME);
            byte[] b = new byte[getReadSize()];
            int n;
            int ix = 0;
            while((n = f.read(b)) >= 0) {
                for(int i = 0; i < n; i++) {
                    if(b[i] != (byte)(ix % 256)) {
                        throw new Exception("Bad data read - offset " + ix + " expected " + (byte)(ix % 256) + " found " + b[i]);
                    }
                    ix++;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    abstract int getReadSize();
}
abstract class BufferedReadTest extends GenericReadTest {
    void readAndCheck() throws Exception {
        try {
            BufferedInputStream f = new BufferedInputStream(new FileInputStream(ReadTest.FILE_NAME));
            byte[] b = new byte[getReadSize()];
            int n;
            int ix = 0;
            while((n = f.read(b)) >= 0) {
                for(int i = 0; i < n; i++) {
                    if(b[i] != (byte)(ix % 256)) {
                        throw new Exception("Bad data read - offset " + ix + " expected " + (byte)(ix % 256) + " found " + b[i]);
                    }
                    ix++;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    abstract int getReadSize();
}
abstract class NioReadTest extends GenericReadTest {
    void readAndCheck() throws Exception {
        try {
            FileChannel f2 = (new FileInputStream(ReadTest.FILE_NAME)).getChannel();
            ByteBuffer f = f2.map(FileChannel.MapMode.READ_ONLY, 0, 10000000);
            byte[] b = new byte[getReadSize()];
            int ix = 0;
            while(ix < 10000000) {
                f.get(b);
                for(int i = 0; i < b.length; i++) {
                    if(b[i] != (byte)(ix % 256)) {
                        throw new Exception("Bad data read - offset " + ix + " expected " + (byte)(ix % 256) + " found " + b[i]);
                    }
                    ix++;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    abstract int getReadSize();
}
abstract class RandomAccessReadTest extends GenericReadTest {
    void readAndCheck() throws Exception {
        try {
            RandomAccessFile f = new RandomAccessFile(ReadTest.FILE_NAME, "r");
            byte[] b = new byte[getReadSize()];
            int n;
            int ix = 0;
            while((n = f.read(b)) >= 0) {
                for(int i = 0; i < n; i++) {
                    if(b[i] != (byte)(ix % 256)) {
                        throw new Exception("Bad data read - offset " + ix + " expected " + (byte)(ix % 256) + " found " + b[i]);
                    }
                    ix++;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    abstract int getReadSize();
}
class UnbufferedSmallReadTest extends UnbufferedReadTest {
    int getReadSize() {
        return 10;
    }
    String getType() {
        return "Unbuffered small reads";
    }
}
class UnbufferedLargeReadTest extends UnbufferedReadTest {
    int getReadSize() {
        return 1000000;
    }
    String getType() {
        return "Unbuffered large reads";
    }
}
class BufferedSmallReadTest extends BufferedReadTest {
    int getReadSize() {
        return 10;
    }
    String getType() {
        return "Buffered small reads";
    }
}
class BufferedLargeReadTest extends BufferedReadTest {
    int getReadSize() {
        return 1000000;
    }
    String getType() {
        return "Buffered large reads";
    }
}
class NioSmallReadTest extends NioReadTest {
    int getReadSize() {
        return 10;
    }
    String getType() {
        return "Nio small reads";
    }
}
class NioLargeReadTest extends NioReadTest {
    int getReadSize() {
        return 1000000;
    }
    String getType() {
        return "Nio large reads";
    }
}
class RandomAccessSmallReadTest extends RandomAccessReadTest {
    int getReadSize() {
        return 10;
    }
    String getType() {
        return "Random access small reads";
    }
}
class RandomAccessLargeReadTest extends RandomAccessReadTest {
    int getReadSize() {
        return 1000000;
    }
    String getType() {
        return "Random access large reads";
    }
}


Unbuffered small reads : 1750
Unbuffered small reads : 1766
Unbuffered small reads : 1781
Unbuffered large reads : 188
Unbuffered large reads : 187
Unbuffered large reads : 172
Buffered small reads : 344
Buffered small reads : 328
Buffered small reads : 313
Buffered large reads : 172
Buffered large reads : 188
Buffered large reads : 187
Nio small reads : 453
Nio small reads : 453
Nio small reads : 438
Nio large reads : 156
Nio large reads : 141
Nio large reads : 125
Random access small reads : 1797
Random access small reads : 1890
Random access small reads : 1891
Random access large reads : 172
Random access large reads : 172
Random access large reads : 187
Avatar billede _carsten Nybegynder
18. oktober 2004 - 20:51 #10
--> Arne, det var da en kanon test som vil noget

Den taler jo sit tydelige sprog, Nio og Buffered går man ikke fejl af.

Kanon !  :)
Avatar billede jespersahner Nybegynder
19. oktober 2004 - 22:02 #11
-> arne_v: Det er fornemt. Tak for den grundige gennemgang! Smid et svar, så kvitterer jeg med nogle point.
Avatar billede arne_v Ekspert
19. oktober 2004 - 22:05 #12
svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester