Hallo,
ich beschäftige mich seit ein paar Tagen mit NoSQL System (speziell CouchDB und Cassandra). Bis jetzt habe ich viel mit iBatis und MySQL gemacht. Da die Java Clients für Cassandra entweder noch nicht ausgereift sind, oder ich einfach nur zu bl...d bin diese zu benutzen habe ich mit CouchDB4J gearbeitet. Ich war ganz angetan, vor allem weil die Werbebotschaften Performance, Einfachheit und ideal für Webanwendungen versprechen. Leider habe ich keinen Performancevergleich zwischen MySQL und CouchDB im Internet gefunden. Also habe ich selbst einen einfachen Performancetest erstellt. Hier mal die Bedingungen:
Hardware für Server und Client: VMWare Server 1 auf Windows XP Rechner, 512 MB RAM
Betriebssystem Datenbankserver: 2x Ubuntu 10 Server Grundinstallation
Anpassungen für CouchDB auf ersten Ubuntuserver:
- apt-get install couchdb
- bind_address in default.ini auf 0.0.0.0 geändert
- hier wird folgendes Dokument immer wieder geschrieben [{"data":"40 Zeichen Text"}]
Anpassungen für MySQL auf zweiten Ubuntuserver:
- apt-get install mysql-server
- bind_address in my.cnf auf 0.0.0.0 geändert
- Tabelle erstellt CREATE TABLE data (data VARCHAR(50),FULLTEXT (data));
Client: Windows XP, 1GB Ram
CouchDB Client:CouchDB4J
MySQL Client: iBatis
Test1: Schreiben von einer Million Daten a 40 Zeichen
Test2: Lesen von 1000, 10.000, 30.000, 100.000 Daten a 40 Zeichen
Im Anhang seht ihr, wie lange es dauert, um 1000 Daten a 40 Zeichen in die Datenbank zu schreiben in Abhängigkeit der Anzahl bereits vorhandener Daten. Ich finde es interessant, dass CouchDB mit der größer werdenden Menge der Daten immer langsamer wird, wogegen MySQL zum Ende etwas langsamer wird, aber eigentlich stabil bleibt.
Interessant ist dabei auch die Datenmenge. Normalerweise erzeuge ich rund 45 MB Daten (1.000.000 * 40 * 1Byte/Char)Byte. MySQL hat dann 48 MB Daten in der Datenbank liegen und 78 MB an Indexes. Die Datenbank in CouchDB ist 2.000MB !!!!! groß.
Das Lesen der Daten ist auch interessant:
CouchDB
1.000 Texte mit 40 Zeichen 250ms
10.000 Texte mit 40 Zeichen 1.735ms
30.000 Texte mit 40 Zeichen 4.704ms
100.000 Texte mit 40 Zeichen HeapSpace Error
MySQL
1.000 Texte mit 40 Zeichen 406ms
10.000 Texte mit 40 Zeichen 828ms
30.000 Texte mit 40 Zeichen 1.030ms
100.000 Texte mit 40 Zeichen 1.700ms
Noch ein Hinweis dazu: Bei CouchDB habe ich nur die Indizies geladen. Die eigentlichen Daten müsste ich noch extra nachladen. Ich habe natürlich auch das versucht, aber da braucht CouchDB 3x so lang und der Heap Space Error erscheint schon nach 12.000 Texten. Bei MySQL hatte ich die Daten nach den Zeiten in einer java.util.List vorliegen.
Nun frage ich mich, wo hier die versprochenen Performancevorteile sind? Was meint ihr dazu? Ich habe das Gefühl, dass sich die Vorteile von NoSQL auf "Schemalos" beschränken. Oder habe ich da zufällig den miesesten Vertreter erwischt?
So,hier noch der Quellcode:
MySQL Reader
SQLCode SELECT:
MySQL Writer
SQLCode INSERT:
CouchDBReader
CouchDBWriter
Hilfsklasse Text:
ich beschäftige mich seit ein paar Tagen mit NoSQL System (speziell CouchDB und Cassandra). Bis jetzt habe ich viel mit iBatis und MySQL gemacht. Da die Java Clients für Cassandra entweder noch nicht ausgereift sind, oder ich einfach nur zu bl...d bin diese zu benutzen habe ich mit CouchDB4J gearbeitet. Ich war ganz angetan, vor allem weil die Werbebotschaften Performance, Einfachheit und ideal für Webanwendungen versprechen. Leider habe ich keinen Performancevergleich zwischen MySQL und CouchDB im Internet gefunden. Also habe ich selbst einen einfachen Performancetest erstellt. Hier mal die Bedingungen:
Hardware für Server und Client: VMWare Server 1 auf Windows XP Rechner, 512 MB RAM
Betriebssystem Datenbankserver: 2x Ubuntu 10 Server Grundinstallation
Anpassungen für CouchDB auf ersten Ubuntuserver:
- apt-get install couchdb
- bind_address in default.ini auf 0.0.0.0 geändert
- hier wird folgendes Dokument immer wieder geschrieben [{"data":"40 Zeichen Text"}]
Anpassungen für MySQL auf zweiten Ubuntuserver:
- apt-get install mysql-server
- bind_address in my.cnf auf 0.0.0.0 geändert
- Tabelle erstellt CREATE TABLE data (data VARCHAR(50),FULLTEXT (data));
Client: Windows XP, 1GB Ram
CouchDB Client:CouchDB4J
MySQL Client: iBatis
Test1: Schreiben von einer Million Daten a 40 Zeichen
Test2: Lesen von 1000, 10.000, 30.000, 100.000 Daten a 40 Zeichen
Im Anhang seht ihr, wie lange es dauert, um 1000 Daten a 40 Zeichen in die Datenbank zu schreiben in Abhängigkeit der Anzahl bereits vorhandener Daten. Ich finde es interessant, dass CouchDB mit der größer werdenden Menge der Daten immer langsamer wird, wogegen MySQL zum Ende etwas langsamer wird, aber eigentlich stabil bleibt.
Interessant ist dabei auch die Datenmenge. Normalerweise erzeuge ich rund 45 MB Daten (1.000.000 * 40 * 1Byte/Char)Byte. MySQL hat dann 48 MB Daten in der Datenbank liegen und 78 MB an Indexes. Die Datenbank in CouchDB ist 2.000MB !!!!! groß.
Das Lesen der Daten ist auch interessant:
CouchDB
1.000 Texte mit 40 Zeichen 250ms
10.000 Texte mit 40 Zeichen 1.735ms
30.000 Texte mit 40 Zeichen 4.704ms
100.000 Texte mit 40 Zeichen HeapSpace Error
MySQL
1.000 Texte mit 40 Zeichen 406ms
10.000 Texte mit 40 Zeichen 828ms
30.000 Texte mit 40 Zeichen 1.030ms
100.000 Texte mit 40 Zeichen 1.700ms
Noch ein Hinweis dazu: Bei CouchDB habe ich nur die Indizies geladen. Die eigentlichen Daten müsste ich noch extra nachladen. Ich habe natürlich auch das versucht, aber da braucht CouchDB 3x so lang und der Heap Space Error erscheint schon nach 12.000 Texten. Bei MySQL hatte ich die Daten nach den Zeiten in einer java.util.List vorliegen.
Nun frage ich mich, wo hier die versprochenen Performancevorteile sind? Was meint ihr dazu? Ich habe das Gefühl, dass sich die Vorteile von NoSQL auf "Schemalos" beschränken. Oder habe ich da zufällig den miesesten Vertreter erwischt?
So,hier noch der Quellcode:
MySQL Reader
Java:
SqlMapClient sm = SQLConnector.getSQLMap();
long start = System.currentTimeMillis();
try {
sm.queryForList("selectMany", 30000);
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("Laufzeit: " + (System.currentTimeMillis()-start) + "ms");
Code:
<select id="selectMany" resultClass="String" parameterClass="Integer">
SELECT * FROM data Limit 0, #value#;
</select>
MySQL Writer
Java:
BufferedWriter writer = null;
SqlMapClient sm = SQLConnector.getSQLMap();
try {
sm.delete("deleteData");
System.out.println("Anzahl Datensaetze in 'Data': " + sm.queryForObject("selectAnzahl"));
} catch (SQLException e) {
e.printStackTrace();
}
long start = System.currentTimeMillis();
int anzahl = 1000;
int durchgaenge = 1000;
String count = null;
try {
writer = new BufferedWriter(new FileWriter("c:\\data.csv"));
for(int j = 0; j < durchgaenge; j++){
long startBrocken = System.currentTimeMillis();
try {
sm.startBatch();
for(int i = 0; i < anzahl; i++)
sm.insert("insertData", Text.subtext(40));
sm.executeBatch();
count = (String) sm.queryForObject("selectAnzahl");
} catch (Exception e) {
e.printStackTrace();
}
writer.write(count+","+(System.currentTimeMillis() - startBrocken)+"\r\n");
System.out.println("Durchgang " + j + "/" + durchgaenge + " - Laufzeit: " + (System.currentTimeMillis() - startBrocken) + "ms");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(writer != null)
try {writer.close();}
catch (Exception e1) {e1.printStackTrace();}
}
Code:
<insert id="insertData" parameterClass="String">
INSERT INTO data (data)
VALUES (#data#);
</insert>
CouchDBReader
Java:
long start = System.currentTimeMillis();
ViewResults vr = db.getAllDocumentsWithCount(30000);
System.out.println("Laufzeit: " + (System.currentTimeMillis()-start) + "ms");
CouchDBWriter
Java:
BufferedWriter writer = null;
Session s = new Session("10.164.29.231", 5984);
s.deleteDatabase("manigdni");
s.createDatabase("manigdni");
Database db = s.getDatabase("manigdni");
long start = System.currentTimeMillis();
int anzahl = 1000;
int durchgaenge = 1000;
Document [] docs = new Document[anzahl];
try {
writer = new BufferedWriter(new FileWriter("c:\\couchdb.csv"));
for(int j = 0; j < durchgaenge; j++){
long startBrocken = System.currentTimeMillis();
for(int i = 0; i < anzahl; i++){
docs[i] = new Document();
docs[i].put("text", Text.subtext(40));
}
try {
db.bulkSaveDocuments(docs);
} catch (Exception e) {e.printStackTrace();}
try {
Document d = db.getDatabaseInfo();
writer.write(d.get("doc_count").toString()+","+
d.get("disk_size").toString()+","+
(System.currentTimeMillis() - startBrocken)+"\r\n");
System.out.println("Durchgang " + j + "/" + durchgaenge + " - Laufzeit: " + (System.currentTimeMillis() - startBrocken) + "ms");
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(writer != null)
try {writer.close();}
catch (Exception e1) {e1.printStackTrace();}
}
System.out.println("Laufzeit: " + (System.currentTimeMillis()-start) + "ms");
Hilfsklasse Text:
Java:
public class Text {
private static String text = "ca 1000 Wörter aus einem Buch sind eigentlich hier drin";
Random rand = new Random();
public static String subtext(int anzahlZeichen){
Random rand = new Random();
int pos = rand.nextInt(text.length()-anzahlZeichen);
return text.substring(pos, pos+anzahlZeichen);
}
}
Zuletzt bearbeitet: