Eigener Sqlite Datentyp

Du bist neu in der Welt von C++? Dann schau hier herein!
Nightrush
Beiträge: 13
Registriert: 31. Juli 2013 09:59

Eigener Sqlite Datentyp

Beitrag von Nightrush »

Hallo Leute,

ich habe folgendes Problem. Ich habe eine Klasse die hauptsächlich zum lagern von Daten dient, in der weiter eigene Klassen, gefüllte Vectoren etc... liegen. Wie kann ich diese in die Datenbank schreiben und wieder herausbekommen ? Ich habe es schon mit Q_DECLARE_METATYPE(...) und den entsprechenden Funktionen in QVariant versucht leider ohne Erfolg.

Viele Grüße,
Nightrush
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Eigener Sqlite Datentyp

Beitrag von Christian81 »

Das müsste dann ein Custom-Datatype sein den auch SQLite kennt - das geht so nicht wirklich.
Am sinnvollsten ist es, die Daten in ein QByteArray zu serialisieren und als Blob zu speichern.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Nightrush
Beiträge: 13
Registriert: 31. Juli 2013 09:59

Re: Eigener Sqlite Datentyp

Beitrag von Nightrush »

Und wie mache ich das am besten ?
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Eigener Sqlite Datentyp

Beitrag von Christian81 »

C++ Grundlagenn, siehe z.B. http://www.functionx.com/cpp/articles/serialization.htm
Oder Qt benutzen mittels QDataStream
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Nightrush
Beiträge: 13
Registriert: 31. Juli 2013 09:59

Re: Eigener Sqlite Datentyp

Beitrag von Nightrush »

Super Danke, werde das mal ausprobieren :)
Nightrush
Beiträge: 13
Registriert: 31. Juli 2013 09:59

Re: Eigener Sqlite Datentyp

Beitrag von Nightrush »

Also habe es jetzt sowhol mit dem QDatastream als auch mit QVariant (http://qt-project.org/doc/qt-4.8/tools-customtype.html) probiert. Was ich auch mach es klappt nicht. Das fängt schon damit an, dass mir "sizeof(...)" sagt das Object wäre 172 Byte groß, aber eine der eignen Klassen innerhlab der Klasse müsste deutlich mehr als 2 MB haben und das ist noch lange nicht alles... .
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Eigener Sqlite Datentyp

Beitrag von Christian81 »

Ich glaube Du solltest dich mal etwas genauer mit C++ und Serialisieren beschäftigen... einfach die Klasse in ein QByteArray packen ist definitiv nicht der richtige Weg und auch nicht das, was im Link und in der QDataStream-Doku beschrieben ist ...
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Nightrush
Beiträge: 13
Registriert: 31. Juli 2013 09:59

Re: Eigener Sqlite Datentyp

Beitrag von Nightrush »

Der Tipp mit Serialisieren war gut, ich kann nun alles speichern und wieder auslesen mit einer ausnahme.
Am QVarLengthArray scheitert es noch, habe es so versucht

Code: Alles auswählen


int main(int argc, char *argv[])
{
    QByteArray byteArray;

    QDataStream streamIn(&byteArray,QIODevice::WriteOnly);
    QDataStream streamOut(&byteArray,QIODevice::ReadOnly);

    QVarLengthArray<int> varArray;

    varArray.append(455);
    varArray.append(788);
    varArray.append(2235);

    int* arrayData = varArray.data();

    qDebug() << "VarArray1 count: " << varArray.count();
    qDebug() << "Size(in)(Byte): " << sizeof(arrayData[0]) *  varArray.count();

    char* data =  new char[12];

    memcpy(data,arrayData,12);

    streamIn << 12;
    streamIn << data; // write in the data

    QVarLengthArray<int> varArray2;
    uint size;
    streamOut >> size;

    char* dst = new char[size];
    memset(dst,0,size);

    streamOut.readRawData(dst,size);

    qDebug() << "Size(out): " << size;

    int* intPtr = new int[size/4];

    memcpy(intPtr,dst,3);
    
    varArray2.append(intPrt,3);

    qDebug() << "VarArra2 count:: " << varArray2.count();
    qDebug() << "First: " << varArray2.first() ;

    return 0;
}
Habe auch eine Menge abwandlungen davon probiert es es geht einfahc nicht. Wie könnte das gehen ?
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Re: Eigener Sqlite Datentyp

Beitrag von RHBaum »

Generell paar Anmerkungen:

1.) QVarLengthArray iss ne Kruecke :-) Solltest wirklich nur verwenden wenn sowas brauchst. Ich hab den Fall nocht nie gehabt :-)
2.) Du verwendest schon "brav" Container, warum mixt du das dann noch mit new (C Style allokation). ? unter c++ solltest du new nur noch ganz selten brauchen, und wenn dann in verbindung mit smartpointer. QObject Klassen sind eine der Ausnahmen (deshalb ist die Qt Syntax nicht wirklich optimales c++).
3.) bisschen mehr RAII :-) den streamout z.b. brauchst viel spaeter erst definieren :-)

Nimm statt Vararry nen Vector.
Nen Vector hat auch ne Methode den Datenbereich zu resizen. Du hasst hier eh IO Operationen (sqlyte auf filesystem) da ist der overhead des einmaligen news im vector dein geringstes Problem, performancetechnisch.
und du machst es dir zu kompliziert, Qt sollte fuer QVector und PODs (plain old data - C-kompatible structuren) die operatoren fuer DataStream kennen :-)

Code: Alles auswählen

int main(int argc, char *argv[])
    {
        QByteArray byteArray;

        QDataStream streamOut(&byteArray,QIODevice::WriteOnly);
		
		QVector<int> myDynamicIntArray(3,0); /// gleich auf groesse 3 allokieren und mit 0 belegen 
		myDynamicIntArray[0] = 455;
		myDynamicIntArray[1] = 788;
		myDynamicIntArray[2] = 2235;

		qDebug() << "myDynamicIntArray count: " << myDynamicIntArray.count();
		/// sizeof(arrayData[0]) statt von varibalen defs lieber den size vom typ nehmen, das kann schneller sein ... 
        qDebug() << "possible Size(in)(Byte): " << sizeof(int) *  varArray.count(); /// nen vector kann und wird meistens mehr speicher allokieren als er momentan grad an membern haelt, deswegen ist diese Speicherangabe sehr vorsichtig zu bewerten !
	
		/// Speichern in nen Datasream geht total easy ! 
		streamOut << myDynamicIntArray; /// das wars ! 
		
		
		/// rauslesen geht genau so einfach ! 
		QDataStream streamIn(&byteArray,QIODevice::ReadOnly);
		QVector<int>  myDynamicIntArray2;
		streamIn >> myDynamicIntArray2; 
		
		qDebug() << "myDynamicIntArray2 count:: " << myDynamicIntArray2.count();
		if(!myDynamicIntArray2.isEmpty())
		{
			qDebug() << "First: " << myDynamicIntArray2.first() ; /// zugriffe auf elmente immer absicheren, wenn das array mal leer gibts sonst laufzeitfehler
		}
	
	}
Noch mal generell zu QDataStreams!
Das DIng ist unheimlich praktisch, wenn du im Qt - QDataStream Context bleibst.
Also wenn du nur mit QDataStream auf die serialisierten daten zugreifst.
Musst du die mit anderen methoden (anderes programm ohne QT z.b.) auslesen, solltest Du QDataStream nicht nehmen, sondern selber binaer auf dem Device (read write) schreiben.
QDataStream speichert mehr infos weg, als wie du selber schreibst(version informatioen, LSB/MSB und mehr), das koennte dir die serialisierung zerhauen wenn mit was anderes ausliest ...

Ciao ...
Nightrush
Beiträge: 13
Registriert: 31. Juli 2013 09:59

Re: Eigener Sqlite Datentyp

Beitrag von Nightrush »

1.) Erstmal danke für die umfangreiche Antwort :D. Der Grund warum ich dne QVarLengthArray verwende ist dieser hier:

Code: Alles auswählen

    QTime time;
    time.start();
    double timeAll;

//    QVector<int> container1(1000000,0);
//    QVector<int> container1(1000000);
    QVarLengthArray<int> container1(1000000);


    for(int j = 0;j<50;j++)
    {
        for(int i = 0;i<1000000;i++)
            container1[i] = i;

        timeAll += time.restart();
    }

    timeAll /= 50;

    qDebug() << "Mean time elapsed: " << timeAll;
    
    //QVector<int> container1(1000000,0):            38.68
    //QVector<int> container1(1000000):               38.06
    //QVarLengthArray<int> container1(1000000) :  6.54

Die Geschwindigkeit meines aktuellen Programms hängt allein davon ab wie schnell ein Container gefüllt und gelesen wird und in der hinsicht kann QVector QVarLengthArray einfach nicht das Wasser reichen. (Es sein denn ich mache irgendetwas falsch :D )

2.) Ich habe an der Stelle new verwendete weil ich einfach keine Ideen mehr hatte wie ich die Daten des QVarLengthArrays abspeichern kann. Das mit den Smartpointer muss ich mir langsam mal angewöhnan hab mit denen noch nie wirklich was gemacht, wäre aber mit Sicherheit sinnvoll und mal an der Zeit :D
Nightrush
Beiträge: 13
Registriert: 31. Juli 2013 09:59

Re: Eigener Sqlite Datentyp

Beitrag von Nightrush »

Ok hab noch einen Test gemaht und es ist am schnellesten wenn ich einen std::vector verwende und dann diesen am Ende mit QVecto<T>::fromStdVector() zu einem QVector mache (Die Variante ist ca. 10x schneller als mit einem QVector zu arbeiten), aber wieso ist der QVector im vergleich zum std::vector so langsam ? Hab den selben Code wie in meinem letzten Post verwendet nur eben mit std::vector. :)
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Re: Eigener Sqlite Datentyp

Beitrag von RHBaum »

Ich hab keine ahnung was die Teile im Hintergrund machen ....
Hasst du auch im release Build (mit optimierung) gemessen ?

QVarLengthArray<T,i> ist ein pedant zum guten alten T myArray
mit etwas mehr verwaltungsinfos drumherum.
Der legt halt alles aufm stack an ....

ein
std::vector<T> mv(i,T())

legt die teile alle ueber den allocator aufm heap an, aber in einem rutsch, d.h. das ding macht genau 1 new mehr, legt die daten dann aber aufm freestor statt aufm stack an (stack kann begrenzt sein)

beim zugriff wiederum sollt es wiederum keinen unnerschied machen, wo die teile liegen ...
der [] operator auf nen std::vector sollt nicht signifikant langsammer sein als der aufm stack-Array !
bei nem QVector sollt es also auch nicht so nen unnerschied machen ....

die frage ist, wie genau dich auf die messung verlassen kannst (hintergrund prozesse oder aehnliches) aber 50 reihen sollt schon einiges glätten ...
eine frage ist noch, ob der compiler nicht deinen schleifendurchlauf optimiert, oder parallelisiert.


lass mal mit

int container3[1000000]

laufen, der sollt definitiv der schnellste sein (wenn die 4000000 byte aufn stack passen)
aber der sollt such nur signifikant beim anlegen (construktor) zu std::vector unterscheiden, in der schleife sollt der vector aehnlich schnell sein (oder dein compiler ist mies, oder zu gut, und optimiert ne menge weg) :-)

Welcher compiler, welche stl version etc waer auch intressant.
Warum QVector so failt , keine ahnung ... sollt eigentlich nicht sein ...

ciao
Nightrush
Beiträge: 13
Registriert: 31. Juli 2013 09:59

Re: Eigener Sqlite Datentyp

Beitrag von Nightrush »

Compiler: MinGW4.8
OS: Windows 7 64Bit
Prozessor: i5-3470
Qt-Version: 5.1

Der selbe Test:

//Debug (1.000.000)
//QVector<int> container(1000000): 37.44
//QVarLengthArray<int> container(1000000): 6.56
//std::vector<int> container(1000000): 3.42
//int container[1000000] : stürtzt im Debug ab

//Release (1.000.000)
//QVector<int> container(1000000): 0.64
//QVarLengthArray<int> container(1000000): 0.32
//std::vector<int> container(1000000): 0.32
//int container[1000000]: 0.00 ....

//Release (100.000.000)
//QVector<int> container(100000000): 75.82
//QVarLengthArray<int> container(100000000): 39.94
//std::vector<int> container(100000000): 40.88
//int container[100000000]: 0.00 ?!?!?!?

Was ich auch versucht habe Die Zeit für /int container[...] blieb immer gleich (0), und irgendwo zwischen 500.000.000 und 550.000.000 meinte der Compiler das wäre zu viel. std::vector ist zwar nichtmehr 10 mal so schnell wie QVector aber fast doppelt so schnell ist eigentlich auch schon Grund genug...
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Re: Eigener Sqlite Datentyp

Beitrag von RHBaum »

Ich trau den QTime nicht so ... ned das da "rundungsfehler" drinn hasst

besser zur zeitmessung das rtc register des processors direkt abfragen und die "Ticks" als zeitgrundlage nehmen ... millisekunden sind in kleineren steps zu ungenau ...
unter windows/winapi geht das mit dem "::QueryPerformanceCounter"

for(int i = 0;i<1000000;i++)
container1 = i;

und keine ahung wie der gcc hier optimieren kann, wenn er ein zusammenhaengendesarray erkennt ...
villeicht parallelisiert der ... keine ahnung.
Aber 0 ist bissi zu optimistisch. Ich denk eher das QTime verhaut da was ...

Frage nur am rande, hasst du als 32 oder als 64 bit compiliert ?
Nightrush
Beiträge: 13
Registriert: 31. Juli 2013 09:59

Re: Eigener Sqlite Datentyp

Beitrag von Nightrush »

genau das selbe Ergebniss wir vorher..

Code: Alles auswählen


    const int runs = 1000000; //1.000.000


    LARGE_INTEGER ticks;
    LARGE_INTEGER starTick;
    QueryPerformanceCounter(&starTick);



        QVector<int> container(runs);
//        QVarLengthArray<int> container(runs);
//           std::vector<int> container(runs);
//    int container[runs];

    for(int j = 0;j<50;j++)
        for(int i = 0;i<runs;i++)
            container[i] = i;

    QueryPerformanceCounter(&ticks);

    qDebug() << "Mean time elapsed: " << (ticks.QuadPart - starTick.QuadPart)/50;

    //Debug (1.000.000)
    //QVector<int> container(1000000):       121095
    //QVarLengthArray<int> container(1000000):21519
    //std::vector<int> container(1000000):    11364
    //int container[1000000] : stürtzt im Debug ab

    //Release (1.000.000)
    //QVector<int> container(1000000):         2373
    //QVarLengthArray<int> container(1000000): 1863
    //std::vector<int> container(1000000):     1070
    //int container[1000000]:                  0

    //Release (100.000.000)
    //QVector<int> container(100000000):        238490
    //QVarLengthArray<int> container(100000000):186341
    //std::vector<int> container(100000000):    130730
    //int container[100000000]:                  0


Ich denke ich compiliere als 32 bit. 99.87% sicher xD
Antworten