![]() Home Benchmarks Historie Forum Download Helpware Insider Dokumentation Kurs Provider-Infos Impressum |
Die PerformanceBenchmarks sind so eine Sache, meistens messen sie genau das, was man gerade messen will. Bei Internetdatenbanken schneidet die tdbengine aufgrund des ganz direkten Datenbankzugriffs in vielen Fällen sehr gut ab. Im Anhang an dieses Artikels finden Sie ein kleines Benchmark-Programm,
das auf diesem Server (Duron 700, Linux 2.2.16) folgende Ergebnisse liefert:
Die erste Zahl weist darauf hin, dass die tdbengine bei String-Operationen nicht unbedingt rasant ist. Hier wird ein Feld mit 40.000 Zufallsstrings gefüllt. Allerdings wird damit auch Perl seine Probleme haben, denn beide Systeme machen eine saubere dynamische String-Verwaltung. Bei der zweiten Zahl werden ebenfalls 40.000 Zufallsstrings erzeugt, die allerdings nur aus Ziffern bestehen (Vor- und Nachkommateil einer Festkommazahl), anschließen werden die Zahlen in das interne Ansi-Double-Format konvertiert. Da die Zufallsstrings hier kürzer sind, ist auch die Ausführungszeit etwas geringer, denn die interne Zahlenverarbeitung ist recht flott. Die dritte Zahl gibt die Zeit an, in der die zugehörige Datenbank
erzeugt wird. Es werden also 10.000 Datensätze mit jeweils 4 alphanumerischen
und 4 numerischen Datenfeldern erzeugt. Hier die genaue Struktur:
Die vierte Zahl zeigt die Zeit für die Erzeugung eines normalen (=BTree) hierarchischen Index über die ersten beiden Spalten der Tabelle. Die fünfte Zahl zeigt die Zeit füe eine simulierte Suche über den gerade erzeugten Index. Es werden alle 10.000 Datensätze gesucht. Das Ergebnis ist m.E. recht imponierend. Bei der sechsten Zahl kommt noch die Zeit für das Lesen der Datensätze hinzu. Es werden wiederum alle 10.000 Datensätze gesucht und gelesen. Die siebte Zahl gibt die Zeit für die Erzeugung eines kompletten Volltextindex mit Feldinformation an. Die letzte Zahl schließlich gibt die Zeit für eine simulierte feldbezogene Volltext-Suche an. Dabei werden im ersten numerischen Feld 100 Suchen ausgeführt mit folgenden Suchmustern: '00*', '01*', ... '99*'. Dabei werden schließlich alle Datensätze gefunden. Jede einzelne Suche liefert im Schnitt 100 Treffer. Hier zeigt sich, wo die besonderen Stärken der tdbengine liegen. Und hier ist das Programm: MODULE Benchmark
VAR String_Fields : STRING[,]
VAR Number_Fields : REAL[,]
VAR LegalChars : STRING
VAR max : INTEGER = 10000
PROCEDURE RandomString(length : INTEGER) : STRING
VAR result : STRING
VAR i : INTEGER
nloop(i,length-1,result:=result+LegalChars[1+random(system.length(LegalChars))])
RETURN result
ENDPROC
PROCEDURE RandomNumber(p1, p2 : INTEGER) : REAL
VAR s_result, t_result : STRING
VAR r_result : REAL
s_result:=RandomString(p1)
IF p2>0 THEN s_result:=s_result+'.'+RandomString(p2) END
r_result:=val(s_result)
RETURN r_result
ENDPROC
PROCEDURE Fill_String_Fields : REAL
VAR i : INTEGER
VAR now : REAL = system.now
LegalChars:='abcdefghijklmnopqrstuvwxyzäöüß'
nloop(i,max,String_Fields[i,0]:=RandomString(40))
nloop(i,max,String_Fields[i,1]:=RandomString(20))
nloop(i,max,String_Fields[i,2]:=RandomString(10))
nloop(i,max,String_Fields[i,3]:=RandomString(05))
RETURN system.now-now
ENDPROC
PROCEDURE Fill_Number_Fields : REAL
VAR i : INTEGER
VAR now : REAL = system.now
LegalChars:='0123456789'
nloop(i,max,Number_Fields[i,0]:=RandomNumber(10,2))
nloop(i,max,Number_Fields[i,1]:=RandomNumber(05,2))
nloop(i,max,Number_Fields[i,2]:=RandomNumber(10,0))
nloop(i,max,Number_Fields[i,3]:=RandomNumber(05,0))
RETURN system.now-now
ENDPROC
PROCEDURE Create_DataBase : REAL
VAR i, j, database, db_def, db_dat, x : INTEGER
VAR now : REAL = system.now
VAR db_name : STRING
db_def:=rewrite('ramtext')
writeln(db_def,'[STRUCTURE]')
writeln(db_def,'field_1=field_string_1,STRING,40')
writeln(db_def,'field_2=field_string_2,STRING,20')
writeln(db_def,'field_3=field_string_3,STRING,10')
writeln(db_def,'field_4=field_string_4,STRING,05')
writeln(db_def,'field_5=field_number_1,NUMBER,8,2')
writeln(db_def,'field_6=field_number_2,NUMBER,8,2')
writeln(db_def,'field_7=field_number_3,NUMBER,8,0')
writeln(db_def,'field_8=field_number_4,NUMBER,8,0')
close(db_def)
makedir('benchmark')
db_name:='benchmark/benchmark.dat'
delfile(db_name)
MakeDB(db_name,'',0,'ramtext')
db_dat:=opendb(db_name,'',0,15)
i:=0
WHILE i++<=max
readrec(db_dat,0)
nloop(j,3,setfield(db_dat,j+1,String_Fields[i,j]))
nloop(j,3,setrfield(db_dat,j+5,Number_Fields[i,j]))
x:=writerec(db_dat,filesize(db_dat)+1)
END
closedb(db_dat)
RETURN system.now-now
ENDPROC
PROCEDURE Create_Index : REAL
VAR now : REAL = system.now
VAR db_dat : INTEGER
VAR db_name : STRING
db_name:='benchmark/benchmark.dat'
delfile('benchmark/bm.ind')
db_dat:=opendb(db_name,'',0,15)
genindex(db_dat,'$1,$2','bm.ind')
closedb(db_dat)
RETURN system.now-now
ENDPROC
PROCEDURE FindIn_Index : REAL
VAR now : REAL = system.now
VAR db_dat, i, x : INTEGER
VAR db_name : STRING = 'benchmark/benchmark.dat'
db_dat:=opendb(db_name,'',0,0)
WHILE i++<=filesize(db_dat)
x:=findrec(db_dat,String_Fields[i,0]+','+String_Fields[i,1],'bm.ind',1)
IF x=0 THEN cgiwriteln('index_error') END
END
closedb(db_dat)
RETURN system.now-now
ENDPROC
PROCEDURE FindIn_Index_And_Read : REAL
VAR now : REAL = system.now
VAR db_dat, i, x : INTEGER
VAR db_name : STRING = 'benchmark/benchmark.dat'
db_dat:=opendb(db_name,'',0,0)
WHILE i++<=filesize(db_dat)
x:=findrec(db_dat,String_Fields[i,0]+','+String_Fields[i,1],'bm.ind',1)
IF x=0 THEN cgiwriteln('index_error') ELSE readrec(db_dat,x) END
END
closedb(db_dat)
RETURN system.now - now
ENDPROC
PROCEDURE Create_Fulltext_Index : REAL
VAR now : REAL = system.now
VAR db_dat, index_dat, rel_dat, x : INTEGER
VAR db_name, index_name, rel_name : STRING
db_name:='benchmark/benchmark.dat'
index_name:='benchmark/index.dat'
rel_name:='benchmark/index.rel'
delfile(index_name)
delfile(rel_name)
genlist(index_name)
genrel('benchmark','index',rel_name)
db_dat:=opendb(db_name,'',0,0)
index_dat:=opendb(index_name,'',0,15)
rel_dat:=opendb(rel_name,'',0,15)
x:=scanrecs(db_dat,index_dat,rel_dat,fields("complete"))
closedb(rel_dat)
closedb(index_dat)
closedb(db_dat)
RETURN system.now-now
ENDPROC
PROCEDURE Find_Fulltext_Index : REAL
VAR now : REAL = system.now
VAR db_dat, index_dat, rel_dat, x, i, j : INTEGER
VAR db_name, index_name, rel_name, searchstr : STRING
db_name:='benchmark/benchmark.dat'
index_name:='benchmark/index.dat'
rel_name:='benchmark/index.rel'
db_dat:=opendb(db_name,'',0,0)
index_dat:=opendb(index_name,'',0,0)
rel_dat:=opendb(rel_name,'',0,0)
WHILE i<10 DO
j:=0
WHILE j<10 DO
searchstr:='field_number_1:'+str(i)+str(j)+'*'
x:=x+MarkTable(db_dat,index_dat,searchstr,'0123456789','',0,rel_dat)
j++
END
i++
END
IF x<>max THEN cgiwriteln('fulltext_index_error') END
closedb(rel_dat)
closedb(index_dat)
closedb(db_dat)
RETURN system.now-now
ENDPROC
PROCEDURE Main
cgiwriteln('content-type: text/plain')
cgiwriteln('')
cgiwriteln('tdbengine: system performance')
cgiwriteln('')
InitArray(String_Fields[max,3]); InitArray(Number_Fields[max,3]);
cgiwriteln(timestr(Fill_String_Fields,2)+' '+'Fill_String_Fields')
cgiwriteln(timestr(Fill_Number_Fields,2)+' '+'Fill_Number_Fields')
cgiwriteln(timestr(Create_DataBase,2)+' '+'Create_DataBase')
cgiwriteln(timestr(Create_Index,2)+' '+'Create_Index')
cgiwriteln(timestr(FindIn_Index,2)+' '+'FindIn_Index')
cgiwriteln(timestr(FindIn_Index_And_Read,2)+' '+'FindIn_Index_And_Read')
cgiwriteln(timestr(Create_Fulltext_Index,2)+' '+'Create_Fulltext_Index')
cgiwriteln(timestr(Find_Fulltext_Index,2)+' '+'Find_Fulltext_Index')
ENDPROC
Hier nochmal tabellarisch die Auswertung
|