Performance CouchDB (NoSQL) vs. MySQL

freez

Top Contributor
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
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");
SQLCode SELECT:
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();}
		}
SQLCode INSERT:
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:

Sonecc

Gesperrter Benutzer
Es ist hinreichend bekannt, dass CouchDB beim Indexen extrem langsam ist

Nachtrag: Die Datenbankgröße ist deshalb so groß, weil die Indizes bei jedem Update des Dokuments kopiert werden müssen. (Hab vor einiger Zeit mal nen Bericht darüber gelesen, weiß aber nimmer wo)
 
Zuletzt bearbeitet:

freez

Top Contributor
Es ist hinreichend bekannt, dass CouchDB beim Indexen extrem langsam ist

Nachtrag: Die Datenbankgröße ist deshalb so groß, weil die Indizes bei jedem Update des Dokuments kopiert werden müssen. (Hab vor einiger Zeit mal nen Bericht darüber gelesen, weiß aber nimmer wo)

Ich date doch aber keine Dokumente ab, sondern erzeuge neue Dokumente. Und auch wenn es der Grund wäre, ist über das 10fache einfach zu viel.
 

Sonecc

Gesperrter Benutzer
Hab mich falsch ausgedrückt...

Bei jeder Veränderung eines Dokuments müssen die Indizes kopiert werden. Also auch bei neu Erstellung von Dokumenten. Das wirkte sich, soweit ich mich erinnere am meisten bei der Erstellung vieler Dokumente aus. CouchDB ist (wie gesagt, alles Erinnerungswerte) auch nicht darauf ausgelegt, viele Dokumente zu erzeugen, sondern sollte eher wenige, dafür aber größere Dokumente nutzen
 

freez

Top Contributor
Ehrlich? Dann muss ich doch mal Cassandra testen. Wenn Facebook so eine Datenbank einsetzt dann sollte nicht so eine Datenflut entstehen ... dann wären die Server schnell voll. Aber ich glaube trotzdem, dass irgendwas nicht stimmt. Entweder ist das Design falsch, es gibt ein Bug oder ich muss noch an einer Schraube drehen.

Ansonsten ist mein Fazit: Lieber MySQL!
 
M

maki

Gast
Standardparameter. Ist aber für den test nicht ganz so wichtig, weil beide mit den gleichen Parametern laufen und das auch ne interessante Aussage ist.
Sorry, aber das ist Blödsinn.

CouchDB4J ist eine Javaanwendung, die Standardeinstellungen für eine 32 Bit JVM sind 64 MiB(inkl. deinem Programm), da hat MySQL sicherlich mehr ;)
Ceteris parabus ist nicht wirklich erreichbar bei so einem Vergleich, aber zumindest sollte man Fair sein und vernünftige Startwerte setzen, so wie sich dein test liest (Heap Space Error) läuft doch bestimmt die ganze Zeit der GC und verfälscht deine Ergebnisse.

Würde Xms und Xmx auf 512m setzen, soviel hat MySQL doch auch mindestens.
 

freez

Top Contributor
Sorry, aber das ist Blödsinn.

CouchDB4J ist eine Javaanwendung, die Standardeinstellungen für eine 32 Bit JVM sind 64 MiB(inkl. deinem Programm), da hat MySQL sicherlich mehr ;)
Ceteris parabus ist nicht wirklich erreichbar bei so einem Vergleich, aber zumindest sollte man Fair sein und vernünftige Startwerte setzen, so wie sich dein test liest (Heap Space Error) läuft doch bestimmt die ganze Zeit der GC und verfälscht deine Ergebnisse.

Würde Xms und Xmx auf 512m setzen, soviel hat MySQL doch auch mindestens.

Ich habe das Gefühl, wir reden von verschiedenen Sachen. CouchDB und MySQL laufen jeweils auf einem Ubuntu Server. Die HeapSpace Meldung stammt von dem JavaClient. Bei CouchDB ist das CouchDB4J und bei MySQL ist es iBatis. Also laufen beide JavaClients mit den gleichen Werten.
 

Cage Hunter

Aktives Mitglied
Also die beiden DB's miteinander zu vergleichen geht so gar nicht^^
Wie bereits gesagt wurde :
CouchDB ist für wenige, aber große Daten/Texte ausgelegt
MySQL ist halt eher die klassische DB für alles irgendwie
Selbst die Architekturen sind unterschiedlich und beide haben ihre Vorzüge und zwar auf verschiedenen Gebieten :)
 
M

maki

Gast
Ich habe das Gefühl, wir reden von verschiedenen Sachen. CouchDB und MySQL laufen jeweils auf einem Ubuntu Server. Die HeapSpace Meldung stammt von dem JavaClient. Bei CouchDB ist das CouchDB4J und bei MySQL ist es iBatis. Also laufen beide JavaClients mit den gleichen Werten.
Das ist schon klar.
Was du aber misst ist so durch den GC verfälscht, dass dabei keine verwertbare Aussage rauskommt, dass deckt sich doch mit deinen Beobachtungen sobald die Datenmenge ansteigt.
Wenn du die Bedingungen wenigstens etwas realistischer machen würdest, könnte man sich zumindest an deinen Messwerten orientieren.
Kenne keine WebApp die mit 64 MiB läuft ;)
So ist das leider nix ganzes und nix halbes.

Nebenbei, Virtualle Maschinen sind nicht gut als Plattformen für "präzise" Performancetests geeignet, da diese sowieso eher ungenau laufen.
 

freez

Top Contributor
Das ist schon klar.
Was du aber misst ist so durch den GC verfälscht, dass dabei keine verwertbare Aussage rauskommt, dass deckt sich doch mit deinen Beobachtungen sobald die Datenmenge ansteigt.
Wenn du die Bedingungen wenigstens etwas realistischer machen würdest, könnte man sich zumindest an deinen Messwerten orientieren.
Kenne keine WebApp die mit 64 MiB läuft ;)
So ist das leider nix ganzes und nix halbes.

Nebenbei, Virtualle Maschinen sind nicht gut als Plattformen für "präzise" Performancetests geeignet, da diese sowieso eher ungenau laufen.

Naja, ich hatte nicht den Anspruch einen perfekten Performance Test zu kreiren. Ich wollte nur einen Eindruck gewinnen, wie sich die beiden bei diesem einen Anwendungsfall "Einfach mal viele kleine Texte speichern" verhalten. Und, VM als Plattform: Ich gebe dir recht ... allerdings lief bei jedem Test immer nur diese eine VM auf dem Server ... also denke ich, dass ich das schon vergleichen kann.
 

freez

Top Contributor
Also die beiden DB's miteinander zu vergleichen geht so gar nicht^^
Wie bereits gesagt wurde :
CouchDB ist für wenige, aber große Daten/Texte ausgelegt
MySQL ist halt eher die klassische DB für alles irgendwie
Selbst die Architekturen sind unterschiedlich und beide haben ihre Vorzüge und zwar auf verschiedenen Gebieten :)

Ja, richtig! Für den Anwendungsfall "Mal eben Millionen Textbrocken speichern" habe ich sie verglichen. Das war ja der Sinn dieser Sache. Ich denke das Performanceverhalten eines DBMS ist zwar nicht das einzigste Kriterium, aber auch für eine Entscheidung wichtig.
 

freez

Top Contributor
So, habe gerade festgestellt, dass Ubuntu nur die Version 0.10.0 von CouchDB mitliefert (ich hatte fälschlicherweise 1.0.0 gelesen). Aktuell ist 1.0.1 und dazwischen ist viel passiert. Ich habe einen ersten kleinen, nicht vergleichbaren Test auf einem anderen System gemacht. Sieht schon viel besser aus. Werde berichten, sobald ich diesen Test in der richtigen Umgebung durchgeführt habe.
 

Ähnliche Java Themen

Neue Themen


Oben