Hallo PostgreSQL-Forum,
ich bin gerade dabei eine Anwendung auf PostgreSQL zu migrieren. Diese Anwendung macht viel mit blobs (bzw. bytea in PostgreSQL). Ich habe nun folgendes Testprogramm geschrieben:
public void doTest() {
try {
Class.forName("org.postgresql.Driver").newInstance();
String cs =
"jdbc :p ostgresql://localhost:5432/testcontent?user=postgres"+
"&password=XXXXX&useUnicode=true" +
"&characterEncoding=ISO-8859-1";
FileInputStream fis = new FileInputStream("/a-big-file");
Connection conn = DriverManager.getConnection(cs);
conn.setAutoCommit(false);
//clean up
PreparedStatement pstmtT =
(PreparedStatement) conn
.prepareStatement("truncate table test_blob");
pstmtT.execute();
pstmtT.close();
pstmtT = null;
int len = 524288;
byte[] buffer = new byte[len];
long seqId = 0L;
long time = System.currentTimeMillis();
long amount = 0L;
int c = 0;
while (true) {
int read = fis.read(buffer, 0 ,len);
if (read > 0) {
amount += read;
ByteArrayInputStream bais =
new ByteArrayInputStream(buffer, 0, read);
PreparedStatement pstmt =
(PreparedStatement) conn
.prepareStatement("insert into test_blob (ID, testblob) values (?,?)");
pstmt.setLong(1, seqId);
pstmt.setBinaryStream(2, bais, (int) read);
pstmt.executeUpdate();
bais.close();
seqId++;
pstmt.close();
pstmt = null;
}
else {
break;
}
}
fis.close();
long timeEnd = System.currentTimeMillis();
System.err.println("Time used: "+(timeEnd-time)+" for "+(amount/1024L/1024L)+" MB");
conn.commit();
timeEnd = System.currentTimeMillis();
System.err.println("Time used: "+(timeEnd-time)+" for "+(amount/1024L/1024L)+" MB");
conn.close();
}
catch (Exception e) {
e.printStackTrace(System.err);
}
}
CREATE TABLE test_blob ( id INTEGER NOT NULL, testblob BYTEA NULL DEFAULT NULL, PRIMARY KEY (id));
Die dazugehörige Tabelle:
Also das Programm macht folgendes: Es ließt eine Datei (137 MB) vom Filesystem und schreibt in die obige Tabelle immer 512KB Blöcke dieser Datei.
Die Performance ist dabei folgende (auf einem recht modernen 3 GHz PC mit 2GB RAM SATA Platten):
Windows: 137 MB in ca. 60 Sekunden
Linux: 137 MB in ca. 23 Sekunden
Exakt derselbe Test mit einer MySQL-InnoDB Datenbank liefert folgende Werte:
Windows: 137 MB in ca. 17 Sekunden
Linux: 137 MB in ca. 13 Sekunden
Ich habe das ganze auch mal mit LargeObjects und OID versucht, die Zahlen sind dabei aber dieselben.
Was mir auch noch aufgefallen ist: Es kommt darauf an, was ich als Blöcke in das bytea reinschreibe, wenn ich ein ZIP File reinschreibe, dauert es sehr lange (siehe oben), wenn ich aber ein TXT-File oder einen buffer mit lauter NULLEN reinschreiben ist es viel viel schneller. Kann es sein, dass die Datenbank beim Speichern irgendwas komprimiert?
Fazit ist: dass die Performance für die geplante Migration ein echtes Problem darstellt, ich hoffe es kann mir jemand ein paar Tips geben, was ich hier machen kann, um die Performance zu steigern.
Viele Grüße
Oliver Schulze