Datenbank für C++



  • Wähle eine Datenbank gemäss deinen Anforderungen an des Speichersystems aus

    Da gebe ich dir grundsätzlich absolut recht, allerdings ist wie gesagt nicht das primäre Ziel eine Datenbank zu finden, die sich perfekt für mein Projekt eignet (daher die beste performance etc. mit sich bringt), sondern mal etwas anderes auszuprobieren. Und wenn dabei die Erfahrung rauskommt, dass es nicht optimal war, weil es z.B. eine NoSQL Datenbank war (oder auch aus irgendwelchen anderen Gründen), dann ist das eine gute Erfahrung gewesen. Es gibt dann auch immer die Option, nochmal die Datenbank zu wechseln.
    Viel mehr möchte ich vermeiden, dass ich später mal in einem richtigen Projekt sitze und es genau um diese Frage geht. welche Datenbank. Irgendjemand sagt dann, lasst uns MongoDb nutzen, das ist der neuste Scheiß und alle großen Firmen setzen daraus ... außerdem viel schneller, flexibler was weiß ich nicht. Würde ich dann sowas entgegenbringne wie

    Für den allgemeinen Fall ist eine SQL Datenbank deutlich geeigneter.

    würde es vermutlich nur heißen, ich wäre konservativ 😉

    Und dann merkt man vlt. während des Projektes, dass SQL wirklich besser gewesen wäre ... naja aber dann ist zu spät, dann steckt Geld, Zeit und ein größeres Team dahinter ... ein Umschreiben auf SQL ist dann vermutlich eher nicht mehr möglich.

    Ich finde es schadet nicht, auch mal was neues auszuprobieren und mehr als nur eine Seite der Medaille zu kennen.

    Aber tatsächlich würd es zunächst wohl erstmal gar keine Relationen geben, später vlt. mal wenige. Was es dafür aber geben wird, sind Objekte mit std::optional membern und soweit ich das verstanden habe, kann eine NoSQL Datenbank oft mit sowas ganz gut umgehen und bietet mehr Flexibilität.

    Das entspricht gar nicht meiner Erfahrung. Das Interface ist üblicherweise zwischen allen Sprachen sehr ähnlich gehalten. Und SQL Datenbank sind sogar untereinander meistens sehr ähnlich in der Schnittstelle. Bist du sicher, dass du da nicht eher ORMs meinst?

    Erfahrung habe ich damit keine, aber es ist etwas, was ich mir vorstellen könnte aus verschiedenen Gründen. Hauptgrund könnte z.B. sein, wenn es gar kein C++ Interface gibt, sondern nur ein C Interface ... Mit C interfaces zu arbeiten ist halt einfach was anderes😅
    Oder wenn man sowas sieht:

    using bsoncxx::builder::basic::kvp;
    using bsoncxx::builder::basic::make_document;
    

    Bei so vielen geschachtelten Namespaces, vergeht einem ja schon irgendwie die Lust.

    Und dann haben Sprachen ja auch unterschiedliche Sprachkonstrukte z.B. kann man bei Node.js json direkt verwenden ohne extra lib etc.

    Aber ja auch z.B. odm würde ich sehr interessant finden ... ohne reflection ist der Spaß da aber vermutlich in C++ auch nur sehr begrenzt ... oder eben auch ORMs.
    Hat damit eig irgendjemand Erfahrung? 🙂


  • Administrator

    @Leon0402 sagte in Datenbank für C++:

    Viel mehr möchte ich vermeiden, dass ich später mal in einem richtigen Projekt sitze und es genau um diese Frage geht. welche Datenbank. Irgendjemand sagt dann, lasst uns MongoDb nutzen, das ist der neuste Scheiß und alle großen Firmen setzen daraus ... außerdem viel schneller, flexibler was weiß ich nicht. Würde ich dann sowas entgegenbringne wie

    Für den allgemeinen Fall ist eine SQL Datenbank deutlich geeigneter.

    würde es vermutlich nur heißen, ich wäre konservativ 😉

    Meine Meinung nach ist es sowieso verloren, wenn die Firma so oberflächlich ihr Speichersystem auswählt. Wenn eine neue Technologie als Ersatz gebracht wird, dann sollten diese gegeneinander beleuchtet werden.

    Das Problem ist halt, wenn deine Applikation nicht für eine nicht-relationale Datenbank geeignet ist, dann wirst du auch gar nicht richtig erleben, was es heisst, eine nicht-relationale Datenbank einzusetzen. Was womöglich eher passieren wird, ist, dass du probierst eine relationale Datenbank in einer nicht-relationalen Datenbank abzubilden. Das ist möglich, aber es ist Unsinn.

    Aber mal von all dem abgesehen. Ich kenne keine NoSQL Datenbank, welche deinen Anforderungen entsprechen würde. Die meisten NoSQL Datenbanken sind für Server gedacht, weil einer der grossen Vorteile dieser Datenbanken ist, dass man sie einfacher hochskalieren kann. Das ist nicht unbedingt etwas, was man lokal auf einem Android Gerät benötigt.

    Wenn man NoSQL einfach nur als Document-Storage oder Key-Value-Storage ansieht, dann kannst du wirklich zu einer SQLite Datenbank mit der JSON Extension greifen. Erstellst dir einfach jeweils Tabellen bestehend aus zwei Spalten von Typ String: Key, Value. Einfach nie Werte zueinander referenzieren. Das kannst du dann überall verwenden. Zur Synchronisation kannst du dann auch einfach die SQLite Datei kopieren.



  • Letzendes möchte ich die Datenbank eig auch hauptsächlich auf einem Server benutzen, es geht nur darum eine offline Benutzung zu ermöglichen.
    Vorgestellt habe ich mir das ganze in etwa so:

    Der Benutzer hat seine eigenen Daten in seiner lokalen Datenbank und kann (optional) seine Daten auf dem server speichern und über dort auch mit anderen leuten teilen. Für die Daten, die also auf dem Server liegen sollen (für teilen oder einfach nur als backup) soll dann bei start der Applikation das ganze mit dem lokalen gesynct werden, sofern Internet zur Verfügung steht.

    Und mangels Erfahrung mit Datenbanken, habe ich mir hier die Frage gestellt, inwiefern die Datenbank dafür support bieten müssen (z.B. für das syncen?). Ob man hier evtl. sogar zu zwei verschiedenen Datenbanken greifen muss? Eine die für server gedacht ist und eine die für lokal geeignet ist?

    @Dravere Was ist denn deiner Meinung nach der perfekte use case für eine NoSql Datenbank? Einfach nur "keine relationen zwischen den Objekten" ... das halte ich für etwas unwahrscheinlich, dass das so ot vorkommt ... und irgendeinen Grund muss es ja geben, dass so viele große Firmen oft genug zu Mongo Db etc. greifen.



  • @Leon0402 sagte in Datenbank für C++:

    @Mechanics sagte in Datenbank für C++:

    Mich hat noch keine NoSql Datenbank überzeugt.

    Welche hast du denn bisher ausprobiert (mit C++?). Was für Probleme gab es denn oder wieso hat es dich nicht überzeugt?

    Dravere hat es im Grunde schon ganz gut beschrieben.
    Immer, wenn ich mir gedacht habe, ich hätte einen Fall, wo ich vielleicht mit einer NoSql Datenbank besser dran wäre, habe ich es mir dann genauer angeschaut (hab mir schon alle möglichen angeschaut), und dann haben die alle doch nicht so wirklich gepasst. Und dann kommt auch dazu, dass Performance für mich eigentlich fast immer ein Argument ist, und schnell sind die meisten dieser Datenbanken nicht, nur evt. einfacher skalierbar.
    Ich setz höchstens ab und zu key-value store Datenbanken für einfache Fälle ein, aber dann hab ich meist auch quasi gar keine Anforderungen an das System.


  • Administrator

    @Leon0402 sagte in Datenbank für C++:

    Und mangels Erfahrung mit Datenbanken, habe ich mir hier die Frage gestellt, inwiefern die Datenbank dafür support bieten müssen (z.B. für das syncen?). Ob man hier evtl. sogar zu zwei verschiedenen Datenbanken greifen muss? Eine die für server gedacht ist und eine die für lokal geeignet ist?

    Aber dann willst du ja nicht die ganze Datenbank synchronisieren sondern nur einen Teil. Weil die Datenbank auf dem Server wird ja wohl die Daten aller Benutzer enthalten, während du auf dem Gerät nur die Daten eines Nutzer möchtest. Das führt auch dazu, dass du unterschiedliche Schemas haben wirst. Es kann sogar soweit gehen, dass es womöglich sinnvoller sein könnte, die Daten lokal auf dem Gerät einfach als eine JSON-Datei oder ähnliches zu speichern. Sich hier auf eine einzige Datenbank probiere zu beschränken, halte ich für keinen guten Ansatz.

    @Dravere Was ist denn deiner Meinung nach der perfekte use case für eine NoSql Datenbank? Einfach nur "keine relationen zwischen den Objekten" ... das halte ich für etwas unwahrscheinlich, dass das so ot vorkommt ... und irgendeinen Grund muss es ja geben, dass so viele große Firmen oft genug zu Mongo Db etc. greifen.

    Caches sind meiner Meinung nach einer der sehr schönen Anwendung von NoSQL Datenbanken. Sehr bekannt dafür ist Redis (z.B. als HTTP Cache). Somit hast du eine NoSQL vor einer SQL Datenbank, um die SQL Datenbank zu entlasten. Beide arbeiten zusammen.

    Eine andere Anwendung wäre Big Data. Wenn du z.B. tausende Sensoren hast, welche alle Daten sammeln und diese an eine Datenbank zur Auswertung schicken sollen. Das skaliert dann auch schön und du kannst zahlreiche weitere Datenbanken starten, um entweder mehr hochladen zu können oder die Auswertung zu beschleunigen.



  • Ich hatte nicht vermutet, dass das Schema groß anders sein sollte. Das ist übrigend auch die einzige Relation, die ich im Kopf erstmal hatte (User zu Daten).

    Quasi

    {
    name: „Max Mustermann“
    ...
    Daten: [
    Foo1 {},
    Foo2 {}
    ...
    ]
    }

    Das einzige, was auf dem server anders wäre, wäre das mann mehr als nur eine json datei für den Benutzer hat🤔
    Das müsste dann doch trotzdem das selbe Schema sein ... in SQL zwei tabellen ... eine für Benutzer ... eine für Daten (Die Daten sind übrigens gleich aufgebaut).

    Über die Möglichkeit einfach gar keine Datenbank für lokal zu haben, habe ich übrigens auch schon nachgedacht.
    Die Idee die Daten einfach nur als jsons zu speichern kam mir dabei in den Sinn. Allerdings wusste ich nicht inwiefern das eine gute Idee ist bzw. wann man das machen kann oder wann man lieber zur Datenbank greift🤔

    Hab mal ein bisschen auf der SQL Lite Seite rumgelesen. Klingt ganz interessant, wohl sehr lightweight und damit auch für mobil sehr geignet. Sie sagen selbst, dass SqlLite nicht für Server in der Regel geeignet ist.
    Eine Überlegung von mir wäre Sql Lite lokal zu nehmen mit der json erweiterung. Beim syncen dann die ganze Daten als json direkt auf den server schicken (Qt bietet das soweit ich weiß an ... glaube dann als byte stream oder so?). Und auf dem server eben eine die json dann wieder einzuspielen🤔



  • Nach ein bisschen rumprobieren und rumlesen, wird es vermutlich für die lokale Datenbank SqlLite werden, das scheint wohl zurzeit einer der besten Datenbanken zu sein für lokale Anwendung, da es performant ist und auf allen Plattformen (vor allem eben auch mobil) läuft.

    Die Frage wäre hier allerdings, welche Variante von SqlLite. An sich wird ja erstmal nur eine C api geboten. Hab diese mal ausprobiert und Spaß macht das wirklich wenig 😃

    Hier würden mir verschiedene Möglichkeiten einfallen, dass ganze etwas angenehmer zu machen.

    Möglichkeit 1: Selbst einen C++ Wrapper schreiben -> Damit könnte man die C Api vermutlich etwas einfacher in der Benutzung machen (z.B. mit Hilfe von Destruktoren ^^)

    Möglichkeit 2: Einen vorhandenen C++ Wrapper nehmen

    Möglichkeit 3: NoSql Datenbank lite version nehmen

    Einige NoSql Datenbanken z.B. Mongo Db, Couchbase bieten mobile Varianten an. Diese bauen überraschenderweise auf sqlLite auf. Das Problem hier nur ist, dass C++ zwar intern von allen Datenbanken immer verwendet wird, aber dennoch selten eine richtige C++ API zur Verfügung steht.

    • https://github.com/couchbaselabs/couchbase-lite-C
      -> Sieht ganz nett aus, C Api mit C++ Wrapper. Problem hierbei ist jedoch, dass das Projekt noch in der Beta Phase ist. Zurzeit gibt es z.B. noch keinen support für android. Auch die Dokumentation lässt zu wünschen übrig insgesamt. Es ist jedoch recht wahrscheinlich, dass das Projekt schnell Fortschritt macht (da die C lib selbst auch nur ein wrapper ist ... der core z.B. unterstützt android bereits etc.)

    @Dravere Wie das json modul in C verwendet wird habe ich allerdings nicht verstanden ^^ Konnte es linken etc. aber dann wusste ich nicht wie man diese Befehle verwenden soll.


  • Administrator

    @Leon0402 Meinst du mit JSON modul jenes von SQLite? Das verwendest du nicht in C. Diese Funktionen sind nachher im SQL verfügbar. Also kannst du z.B. das machen:

    SELECT json_extract(value, '$.property.other') FROM document_store WHERE key = 'key';
    

    Das Resultat ist dann ein String, was im JSON Dokument unter property -> other lag. Wenn du dann in deinem Code mit JSON arbeiten willst, brauchst du eine JSON Bibliothek. Da findest du einige hier: https://json.org/ (unten)

    Eine mögliche moderne Implementierung: https://github.com/nlohmann/json



  • @Leon0402 Hi, wenn's für dich zum üben ist, die sqlite c-Api ist nicht so kompliziert, da kann man ganz gut einen eigenen Wrapper für schreiben. Ansonsten, wenn du einen guten Lightweight Wrapper findest, würden mich deine Erfahrungen damit interessieren. Wir verwenden gerade auch ein Wrapper der aus dem Umfeld eine Gui Bibltiothek stammt (wxWidgets und wxSSLite3), aber eigentlich möchten wir mittelfristig die wxWidgets Abhängigkeiten weg haben.
    Daher würde ich auch zur Vorsicht bei dem QT Wrapper raten, dann hängst du nämlich von QT ab und wenn das "nur" für die Datenbank Schnittstelle ist, ist das schon ein Klotz.
    Aber auch hier gilt, wenn das eh nur für dich ist und du evt. sogar schon QT benutzt, spricht auch da nichts gegen.



  • @Schlangenmensch Hab ich sogar schon mal sehr rudimentär gemacht, wurde im C++ Programmierer behandelt.
    Ja das ist so eine Sache mit den Abhänigkeiten ... Ich verwende sowieso schon QT libs, daher ist das nicht direkt das Problem (wobei eine unabhängige lib natürlich grundsätzlich besser ist, damit ich mir für nicht qt projekte nicht eine andere Suchen muss). Ich muss aber zugeben, dass mir natürlich zusagt, dass es z.B. von qt dann auch direkt ein sql model gibt. Das heißt es ist ziemlich einfach und schick seine Daten dann darzustellen in qml (oder qt widgets).



  • Ich kram mal meinen eignen Thread raus, da ich mal in der Zwischenzeit etwas mit Datenbanken experimentiert habe und mich nun doch wieder die Zweifel einholen 😃

    Diesmal mal ein konkretes Übungs Projekt, für das ich gerne eine Datenbank implementieren würde:

    • Cross Plattform Rezepte App (Linux/Windows/Mac Os, Android / iOS)
    • Es soll einen Server geben fürs synchronisieren, teilen etc. geben
    • Rezepte sollen flexibel und erweiterbar sein ... d.h. optionale Attribute wie Video, Tags etc. sind denkbar

    Nach den Empfehlungen hier, habe ich mal zu Sqlite gegriffen. Einerseits weil es recht kompakt ist und weil es quasi überall läuft.

    Dazu habe ich mich entschieden, das json plugin zu nutzen. Gründe dafür waren, dass ich dachte, es würde sich besser eignenen als klassische Tabellen. Unter anderem, weil die Rezepte ja doch variieren können und man so flexibler ist und weil man Rezepte dann direkt so an den Server senden bzw. vom Server empfangen könnte. Etwas zweifle ich da grade schon dran.

    Aber erstmal meine Implementierung:

    Zunächst die Tabelle

    query.exec("CREATE TABLE IF NOT EXISTS Recipes (name varchar(20) PRIMARY KEY, recipe json)")
    
    namespace {
    void static initDatabase();
    void static syncRecipeToDatabase(const Recipe& recipe);
    void static removeRecipeFromDatabase(const std::string& name);
    std::optional<Recipe> static findRecipeInDatabase(const std::string& name);
    std::vector<Recipe> static getRecipesFromDatabase()
    }
    

    So erstmal das Interface, um direkt auf die Datenbank zugreifen zu können.

    Hier mal zwei Implementierungen, die ich mit der nlohman json lib und Qt gemacht habe:

    void static syncRecipeToDatabase(const Recipe& recipe) {
        QSqlQuery query;
    
        query.prepare("INSERT OR REPLACE INTO Recipes (name, recipe) VALUES(:name , json(:recipe))");
        query.bindValue(":name", QString::fromStdString(recipe.getName()));
        query.bindValue(":recipe", QString::fromStdString(static_cast<nlohmann::json>(recipe).dump()));
        if(!query.exec()) {
            std::cout << query.lastError().text().toStdString() << std::endl;
        }
    }
    
    std::optional<Recipe> static findRecipeInDatabase(const std::string& name) {
        QSqlQuery query;
    
        query.prepare("SELECT * FROM Recipes WHERE name = :name");
        query.bindValue(":name", QString::fromStdString(name));
        if(!query.exec()) {
            std::cout << query.lastError().text().toStdString() << std::endl;
        }
    
        if(!query.next()) {
            return std::nullopt;
        }
    
        return nlohmann::json::parse(query.value(1).toString().toStdString()).get<Recipe>();
    }
    

    Mal abgesehen davon, dass diese Konvertierungen von string zu QString etc. etwas nerven, klappt das ganz gut.

    Dann hatte ich mir noch überlegt, dass man ja caching einführen könnte, damit man nicht immer sofort auf die Datenbank zugreifen muss.

    Dazu habe ich folgendes in meinem ReciperManager:

        constexpr static std::size_t RECIPE_MEMORY_SIZE = 10;
    
        std::deque<Recipe> recipeMemory;
    

    Und entsprechende Methoden auf die dann der Rest der Applikation zugreift, sehen z.B. so aus:

    void RecipeManager::addRecipe(const Recipe& recipe) {
        // If memory is full sync oldest recipe in the memory to the database and then remove it
        if(recipeMemory.size() == RECIPE_MEMORY_SIZE) {
            syncRecipeToDatabase(recipe);
            recipeMemory.pop_front();
        }
    
        recipeMemory.push_back(recipe);
    }
    
    Recipe* RecipeManager::findRecipe(const std::string& name) {
        // Check whether recipe is already in memory
        auto recipeIterator = std::find(recipeMemory.begin(), recipeMemory.end(), name);
        if(recipeIterator != recipeMemory.end()) {
            return &(*recipeIterator);
        }
    
        // Check whether recipe is in database
        auto recipe = findRecipeInDatabase(name);
        if(!recipe.has_value()) {
            return nullptr;
        }
    
        // Add found recipe to memory and return a pointer
        addRecipe(recipe.value());
        return &(recipeMemory.back());
    }
    

    Fragen zu der jetzigen Implementierung:

    • Ergibt mein Database Interface Sinn?
    • Ist das mit dem caching eine gute Idee? Bringt das was, macht man das so?
    • Kann man da was verbessern?

    Generell stelle ich mir die Frage, ob json hier der richtige Weg ist. Was ist z.B. wenn ich dann in meiner App eine Such Funktion habe ... dann suche ich ja mit bestimmten Parametern z.B. Name, Tags (wie vegetarisch), Kosten und erwarte eig. das ich ne Liste zurückbekomme mit Namen der Rezepte und Bild oder so. Halt das, was ich in meiner Ergebnisliste dann anzeige.
    Mit klassischem SQL könnte ich da ja relativ performant komplexe Suchanfragen durchführen ... bei json wäre ich mir da jetzt nicht mehr so sicher.
    -> Vor allem, wenn ich sqlite auf dem server verwende, ist performance ja nicht ganz unwichtig

    Insgesamt habe ich das Gefühl, dass ich einfach keine Ahnung von dem ganzen Thema habe und würde eig. mir gerne etwas Grundwissen aneignenen anstatt euch komplett auszufragen 😃 Es gibt zwar Bücher darüber, wie man jetzt ein SQL Layout macht oder das interface von sql benutzt, aber was mich viel mehr interessiert sind Sachen wie:

    • Embedded Database -> Wie integriere ich sqllite am besten in meine Software (oben ist ja mal ein Versuch ^^) ... macht ein mapping zu echten Objekten Sinn?
    • Caching (oben auch ein Versuch)
    • Wie syncronisiere ich am besten

    ... Also mehr das große ganze drum herum. Wie ich dann konkret sqlite benutze, kann ich mir dann angucken, wenn ich mir erstmal sicher bin, dass es überhaupt die richtige Wahl ist 😃

    Gibt es da Empfehlungen?

    Danke euch schon mal für die Hilfestellung. Ich habe da ja doch schon eine riesige Anzahl an Fragen 😃



  • @Leon0402

    Generell stelle ich mir die Frage, ob json hier der richtige Weg ist.

    Ach



  • @manni66
    Danke für die hilfreiche Antwort 😃 Ich habe ihr schon gemerkt, dass sql im allgemeinen nosql vorgezogen wird. Hat bestimmt auch seine Gründe und mit ein bisschen Erfahrung, werde ich mir da wohl auch noch eine Meinung zu bilden können.
    Am Anfang lässt man sich eben schnell mal vom Trend mitreißen 😵 Ich bitte um Nachsicht



  • Sehr spannendes Thema, aber bitte in einem anderen Thread.


  • Mod

    @Leon0402 sagte in Datenbank für C++:

    Sehr spannendes Thema, aber bitte in einem anderen Thread.

    Die hier nicht mehr sichtbare Diskussion findet man nun hier:
    https://www.c-plusplus.net/forum/topic/351066/ständig-wachsende-komplexität-im-programmiereralltag-fork-aus-datenbank-für-c/9


Anmelden zum Antworten