Forum: PC-Programmierung Datenbankübertragung "grosser" Datenmengen


von Lukas G. (lukas88)


Lesenswert?

Hallo zusammen,

Ich hab da mal ne eigentlich triviale Frage, aber ich stell sie jetzt 
mal, da ich nicht vom Fach bin.


Folgendes:

Es geht darum, eine Datenbank mit SQL/SQlite/MariaDB (also genauer 
gesagt nur eine Tabelle der Datenbank) einer App auf einem Smartphone 
mit einem Server zu Synchronisieren. Also das die Daten auch Online von 
überall her einsehbar und veränderbar sind, und entsprechend auch wieder 
auf der App Synchronisiert werden.

Nun geht es darum WIE ich das am schlausten/effizientischsten mache?

Bis jetzt habe ich  dafür json genutzt. Aber wie übertrage ich 10'000 
Einträge und mehr auf einmal, wenn sie geändert wurden? Klar würde json 
gehen. Aber wie würde man sowas das im Professionellen Bereich 
realisieren?

Wie gesagt, nicht vom Fach. Darum wäre ich um ein paar Inputs froh  : )


lg lukas88

von ms (Gast)


Lesenswert?

Ich würde den einfachsten Weg gehen und nur die DB am Server nutzen. 
Entweder via TLS-gesicherter Verbindung dorthin eine SQL-Verbindung 
aufbauen, oder besser, am Server eine REST API entwickeln über die alles 
läuft und die Abfragen von der DB-Ebene abstrahiert.

Was Du beschreibst (DB-Änderungen am Server mit der DB in der App 
synchronisieren und umgekehrt) klingt nach einem Master/Master Setup. 
Die können aber recht tricky sein und bei der Entwicklung muß das mit 
berücksichtigt werden (Transaktionen, Row- vs Statement-based 
Replication, Locking).

Master/Slave ist simpler, aber dann kann man halt nur in der einen App 
auf dem einen Smartphone oder am Server Änderungen machen, denn der 
Slave ist readonly. Und den Master auf dem Handy laufen lassen ist 
Blödsinn.

Daher, mach eine API.

von Lukas G. (lukas88)


Lesenswert?

ms schrieb:
> Ich würde den einfachsten Weg gehen und nur die DB am Server nutzen.

Geht leider nicht. Mein Hoster verbietet direkte DB anfragen von aussen, 
nur von intern via php&Co. Ist wahrscheinlich eine 
Sicherheitsvorkehrung. Ansonsten wäre eine API auch meine Wahl gewesen. 
Aufwendig, aber wahrscheinlich das Flexibelste und Sauberste.


vielen Dank

von Tilo R. (joey5337) Benutzerseite


Lesenswert?

"Klassisch" kann man natürlich die ganze DB dumpen und kopieren.
Do the math, wie viele Rohdaten hat ein Record? Wie viele Records? Wie 
viel ist das gezippt? Bei 10.000 Records könnte das noch gehen.

Wenn du eines oder mehrere Ziele up to date halten willst brauchst du 
serverseitig eine Art Versionierung, so dass du nur die Änderungen 
übertragen musst, das kann man dann auch mit Zeitstempeln machen.

Die von ms angesprochene Api muss dann z.B. eine "getUpdates"-Funktion 
haben, die ab einem gegebenen Wiederaufsetzpunkt eine begrenzte Anzahl 
von Änderungen liefert und den neuen Wiederaufsetzpunkt, bis zu dem 
diese Daten gehen. Wenn der Client die Daten verarbeitet hat kann er 
sofort oder später nochmal fragen.

von ms (Gast)


Lesenswert?

Lukas G. schrieb:
> Geht leider nicht. Mein Hoster verbietet direkte DB anfragen von aussen,
> nur von intern via php&Co. Ist wahrscheinlich eine
> Sicherheitsvorkehrung. Ansonsten wäre eine API auch meine Wahl gewesen.
> Aufwendig, aber wahrscheinlich das Flexibelste und Sauberste.

Das MySQL nicht von außen einfach so erreichbar ist, ist schon gut so. 
Sollte man auch nicht aufmachen. Aber warum sollte das den Aufbau einer 
API unmöglich machen? Die läuft ja am Server selbst, und dort ist die DB 
dann als localhost erreichbar. Die Anfragen selbst laufen dann via 
HTTPS, und das wird dein Hoster ja wohl erlauben.

Tilo R. schrieb:
> Die von ms angesprochene Api muss dann z.B. eine "getUpdates"-Funktion
> haben,

Und pushUpdates. Das Ganze erfordert dann (wenn man offline arbeiten 
können will) auch den Aufbau einer History. Bei einem Master/Slave wäre 
das das Binlog, aber mit Triggern kann man sich auch eine History 
Tabelle aufbauen und die Änderungen von da in die DB am Server 
übertragen. Wird halt umständlicher.

von ms (Gast)


Lesenswert?

Tilo R. schrieb:
> "Klassisch" kann man natürlich die ganze DB dumpen und kopieren.

Als Nachtrag noch: wenn das ganze Multiuserfähig werden soll, kann man 
sowas knicken. Nichts ist lustiger, als wenn User A einen Datensatz zum 
Editieren offen hat, und währenddessen die DB mit neuen Daten befüllt 
wird. Wenn er dann speichert, ändert er Daten die eventuell anders sind, 
oder noch besser, komplett andere Daten wenn sich die ID ändert (was sie 
nicht sollte, aber man weiß ja nie).

Da braucht es das noch einen Lockmechanismus, und spätestens dann ist 
eigenlich Schluß mit DB austauschen, oder Dump einspielen.

von Ein T. (ein_typ)


Lesenswert?

Lukas G. schrieb:
> Aber wie würde man sowas das im Professionellen Bereich
> realisieren?

Schwierig. Die einfachste Lösung wäre, den beteiligten Tabellen jeweils 
Spalten mit "created" und "last_changed" zu spendieren und dann... 
genau. Dummerweise kannst Du bei nicht verbundenen Datenbanken keine 
konsistenten Primärschlüssel vergeben und mußt Dir obendrein auch noch 
eine Auflösung von Konflikten überlegen. Denn irgendwie mußt Du den Fall 
behandeln, daß der Datensatz 123 in den Instanzen unabhängig voneinander 
geändert wurde.

Leider sagst Du nicht sonderlich viel über Deinen Anwendungsfall, 
deshalb würde ich vermutlich zuerst überlegen, ein Art von REST-API über 
HTTPS zu verwenden und JSON als Datenformat verwenden. Das ist 
vermutlich nicht zu schwierig, kann GZIP zur Kompression der Daten, und 
zudem TLS-Zertifikate für Authentifizierung und Autorisierung verwenden.

von Ein T. (ein_typ)


Lesenswert?

ms schrieb:
> Als Nachtrag noch: wenn das ganze Multiuserfähig werden soll, kann man
> sowas knicken. Nichts ist lustiger, als wenn User A einen Datensatz zum
> Editieren offen hat, und währenddessen die DB mit neuen Daten befüllt
> wird. Wenn er dann speichert, ändert er Daten die eventuell anders sind,
> oder noch besser, komplett andere Daten wenn sich die ID ändert (was sie
> nicht sollte, aber man weiß ja nie).
>
> Da braucht es das noch einen Lockmechanismus, und spätestens dann ist
> eigenlich Schluß mit DB austauschen, oder Dump einspielen.

Das kann man auch ohne Locking lösen, und wird im Distributed Computing 
auch (zwangsläufig) ohne Lock gelöst, etwa indem man jedem Datensatz 
eine Versionsnummer verpaßt und die bei jedem Write hochzählt. 
Gleichzeitig muß der Client die Versionsnummer beim Schreiben 
überprüfen, und wenn der Datensatz inzwischen geändert wurde und die 
Versionsnummer also größer ist als jene, die der Client editiert hat, 
muß der Client den Konflikt lösen. Das ist aber ziemlich aufwändig -- 
und erfordert vor allem, daß absolut alle Clients sich an dieses 
Protokoll halten.

von Kolja L. (kolja82)


Lesenswert?

Wahrscheinlich hilft es dir bei einer bestehenden Datenbank nicht, aber 
das hier ist genau dafür gemacht:   https://couchdb.apache.org/

von Tilo R. (joey5337) Benutzerseite


Lesenswert?

Die ganzen Locking-Probleme und Lösungsmöglichkeiten sind natürlich 
richtig.
Aber wenn die Applikation im ersten Wurf nicht gleich das neue Facebook 
werden soll, geht es vielleicht deutlich einfacher.

Müssen denn überhaupt gleichzeitig mehrere Nutzer schreiben können? 
Falls nicht (oder falls du der einzige schreibende Nutzer bist) --> kein 
Problem.

Falls doch: müssen die die selben Daten bearbeiten? Falls z.B. jeder in 
einem eigenen Bereich arbeitet oder Überschneidungen hinreichend 
unwahrscheinlich sind --> kein Problem

Falls doch: ist die Sache performancekritisch? Falls du z.B. weniger als 
1000 User hast ist es denkbar, schreibende Änderungen serverseitig 
nacheinander abzuarbeiten und dabei eine ändere-von-auf-Logik zu 
verwenden. Falls 2 schreibende Anfragen gleichzeitig kommen muss einer 
warten, und wenn der von-Wert nicht mehr stimmt bekommt er eine 
Fehlermeldung. (Die von ein_typ vorgeschlagene Versionierung 
funktioniert ähnlich)

Wichtiger als das Locking Problem ist sicher zu stellen, dass die API 
kein SQL-Injection-Problem hat.

von Ein T. (ein_typ)


Lesenswert?

Tilo R. schrieb:
> Die ganzen Locking-Probleme und Lösungsmöglichkeiten sind natürlich
> richtig.
> Aber wenn die Applikation im ersten Wurf nicht gleich das neue Facebook
> werden soll, geht es vielleicht deutlich einfacher.
>
> Müssen denn überhaupt gleichzeitig mehrere Nutzer schreiben können?
> Falls nicht (oder falls du der einzige schreibende Nutzer bist) --> kein
> Problem.
>
> Falls doch: müssen die die selben Daten bearbeiten? Falls z.B. jeder in
> einem eigenen Bereich arbeitet oder Überschneidungen hinreichend
> unwahrscheinlich sind --> kein Problem

Im Laufe der Jahre habe ich mich schon mehrmals zu solchen "kein 
Problem"-Ansätzen breitschlagen lassen. Ich bin damit jedes Mal voll auf 
meine Nase gefallen hatte am Ende meistens die begrenzte Freude, meine 
Daten manuell wieder glattziehen zu müssen. Deswegen lasse ich mich 
sowas nur noch dann ein, wenn mein Vorgesetzter oder Kunde schriftlich 
erklärt, daß ich über die Risiken aufgeklärt habe und im Fehlerfall 
nicht mit der Bereinigung beschädigter Datenbestände beauftragt werde. 
Sowas macht nämlich überhaupt gar keinen Spaß, wenn es überhaupt möglich 
ist. Denn wenn die Daten groß genug sind und die Inkonsistenzen erst 
nach längerer Zeit auffallen, dann können die Daten schon so kaputt 
sein, daß man sie nicht mehr reparieren und in einen korrekten, 
konsistenten Zustand überführen kann.

Wie gesagt, leider sagt der TO nicht sonderlich viel über seinen genauen 
Anwendungsfall, also: was das für Daten sind, wie viele Nutzer es geben 
soll, ob ein mobiles Editieren nötig ist, woher die Daten kommen, und so 
weiter. Und ich fürchte, wirklich konstruktiv können wir dazu erst dann 
ausführen, wenn der TO seinen Anwendungsfall genauer erklärt hat.

von Lukas G. (lukas88)


Lesenswert?

ms schrieb:
> Das MySQL nicht von außen einfach so erreichbar ist, ist schon gut so.
> Sollte man auch nicht aufmachen. Aber warum sollte das den Aufbau einer
> API unmöglich machen?

Macht es auch nicht unmöglich. Ist da dann auch Serverintern. Es geht 
einfach nicht direkt über die Datenbank, weil sie eben von aussen nicht 
erreichbar ist.

Bei meinem letzten Hoster konnte ich mich noch direkt in die Datenbank 
Einloggen und Einträge löschen,ändern,hinzufügen, ect.

Aber du hast schon recht. MySQL sollte von aussen nicht erreichbar 
sein,von dem her.

Darum strebe ich auch eine API an.


lg lukas88

von Lukas G. (lukas88)


Lesenswert?

Ein T. schrieb:
> Wie gesagt, leider sagt der TO nicht sonderlich viel über seinen genauen
> Anwendungsfall, also: was das für Daten sind, wie viele Nutzer es geben
> soll, ob ein mobiles Editieren nötig ist, woher die Daten kommen, und so
> weiter. Und ich fürchte, wirklich konstruktiv können wir dazu erst dann
> ausführen, wenn der TO seinen Anwendungsfall genauer erklärt hat.

Hast recht, darum:

-Es geht um eine Private App, soll also nicht in den Play Store, App 
Store,ect

-Bei den Daten geht es Hauptsächlich um Text. Also Datum, Uhrzeit,Notiz, 
Kategorie ect also keine Bilder oder sogar Videos.

-Benutzer sind genau ich vorgesehen. Aber mit der Option, die 
Nutzeranzahl auf maximal 5 zu anzupassen.

-Einträge rechne ich jetzt mal mit minimal 3 pro Tag*365 =1095. Das 
ganze wird aber voraussichtlich die nächsten paar Jahre laufen, und 
sollte auch stetig erweitert werden. Darum die geschätzten 10 000 
Einträge.
-Mobiles editieren möchte ich auch implementieren, sonst mach ja das 
Synchronisieren fast keinen Sinn.

von Εrnst B. (ernst)


Lesenswert?

Lukas G. schrieb:
> Bei den Daten geht es Hauptsächlich um Text. Also Datum, Uhrzeit,Notiz,
> Kategorie ect also keine Bilder oder sogar Videos.

Schau dir an, wie eine Versionsverwaltungssoftware, z.B. git, das macht.

Musst deswegen ja kein git in deine App einbetten (obwohl das auch 
ginge), aber das Prinzip kannst du dir abschauen.

Da kann jeder Nutzer offline an seinem Versionsstand rumwerkeln, und 
trotzdem kriegst du das nachher wieder zusammengefasst in einen 
gemeinsamen Datenbestand.

Konflikte, wenn zwei Leute dieselbe Zeile gleichzeitig bearbeitet haben, 
kannst du ganz pragmatisch lösen: Einfach beide Versionen hintereinander 
schreiben, mit ">>>> Änderung von User A" ... ">>>> Änderung von User B" 
... "<<<<" Markern außenherum.

Je nach Anwendung dann so stehen lassen, oder irgendjemand muss sich das 
ansehen und entscheiden, was stehen bleiben soll.

von Ein T. (ein_typ)


Lesenswert?

Lukas G. schrieb:
> -Bei den Daten geht es Hauptsächlich um Text. Also Datum, Uhrzeit,Notiz,
> Kategorie ect also keine Bilder oder sogar Videos.
>
> -Benutzer sind genau ich vorgesehen. Aber mit der Option, die
> Nutzeranzahl auf maximal 5 zu anzupassen.

Also Multiuser. Da würde ich die Idee mit der Synchronisierung 
vergessen, stattdessen fallen mir auf die Schnelle zwei Lösungen ein:

- serverseitige Versionsnummern und / oder Zeitstempel in der Datenbank, 
mit denen parallele Zugriffe erkannt und Konflikte manuell gelöst 
werden.

- ein temporäres, exklusives Write Lock in der Datenbank. Wenn der 
Client innerhalb der eingestellten Zeit schreibt, wird das Write Lock 
aufgehoben. Wenn nicht (Client wurde abgelenkt, hat die 
Internetverbindung verloren, oder ähnlich), wird es nach der 
eingestellten Zeit freigegeben. Das kann die clientseitige App mit 
entsprechenden Warnungen unterstützen.

Die zweite Lösung erscheint mir deutlich eleganter, weil dabei keinerlei 
Konflikte auftreten können, wenn sie sauber implementiert ist. Sie 
erfüllt aber Deine Forderung nach Synchronisation nicht. Mir fällt 
gerade aber nur eine mögliche Lösung ein, wie eine saubere 
Synchronisation mit mehr als einem Client gelöst werden sollte, und 
die... nein. ;-)

von Lukas G. (lukas88)


Lesenswert?

Also couchdb sieht nicht übel aus. Leider wahrscheinlich für mich etwas 
zu Overkill.

Ich merke aber,das es Komplexer ist als ich bis anhin dachte.

Wahrscheinlich entscheide ich mich für einen Kompromiss.

- Zugriff per API
- "Halb" Synchron. Also Löschen,Hinzufügen,ändern immer aktiv mit der 
Datenbank auf dem Server Synchronisieren. Änderungen die nicht auf dem 
Mobile Device gemacht wurden, werden nur  manuell aktiv durch den 
Benutzter ausgelöst, oder in Zeitlichen Intervallen werden 
Versionsnummern der Datenbank verglichen und gegeben falls 
Synchronisiert.

-Write Lock bei gleichzeitigem Zugriff.Bei Write Lock Kollision bei 
mehreren Usern entweder Fehlermeldung beim Client oder solange warten, 
bis die Datenbank wieder "frei" (vielleicht mit "Warteliste")

Besten dank für eure hilfreichen inputs

lg lukas88

von Ein T. (ein_typ)


Lesenswert?

Kolja L. schrieb:
> Wahrscheinlich hilft es dir bei einer bestehenden Datenbank nicht, aber
> das hier ist genau dafür gemacht:   https://couchdb.apache.org/

Bitte entschuldige, aber könntest Du vielleicht etwas dazu sagen, was 
CouchDB für diesen Anwendungsfall besonders qualifiziert und welche 
Features es anbietet, um das Concurrency-Problem zu lösen?

von Jörg T. (Firma: xShoot Media) (xshoot)


Lesenswert?

Ich arbeite zu 90% mit PHP (Symfony). Hier würde ich ein Feld in die 
Tabelle legen, das den last_change speichert. Und dann über eine 
JSON-API und mit Queued Message Handling das ganze asynchron und sauber 
im Hintergrund synchronisieren... Auf dieser Weise verschicken Programme 
von mir Einzelemails von 7-stelligen Adresslisten ohne Sorgen

von 🐧 DPA 🐧 (Gast)


Lesenswert?

Ich würde jedem Eintrag eine Verisonsnummer geben, die bei jeder 
Änderung per trigger hochgezählt oder geändert wird. Dann würde ich 
einen Endpunkt machen, der alle Verionsnummern entgegennimmt, schaut, ob 
die in der DB anders (oder grösser) sind, und wenn ja, den Eintrag 
zurück gibt. Bei Änderungen des Nutzers muss die Verisonsnummer 
natürlich auch zurückgegeben werden.

Man kann die auch gruppieren. Hat man z.B. den selben counter für alle 
Tabellen, kann man einfach eine Versionsnummer mitgeben, und dann 
einfach überall schauen, wenn (dbversion-clientversion > 0), dann wurde 
es geändert.
Das schreiben skalliert aber nicht gut, sobald man mehrere DBs an 
mehreren Standorten hat, kann man das nicht mehr gut synchronisieren, 
das ist kein kleines Problem. Gibt zwar sicher möglichkeiten, da 
gegenzusteuern. (Das lesen dürfte dafür aber sehr effizient sein.)

Bei Mehreren Versionsnummern und einfachem vergleich ob alt != neu, ist 
das einfacher, da kann man einfach eine UUID generieren, weil man ja 
dort nicht schaut, ist es neuer, und die IDs unabhängig voneinander 
sind. Aber dann muss man die sich halt beim client alle merken, und das 
kann mit seinen eigenen Problemchen kommen.

Was da am einfachsten ist, dürfte stark von der Infrastruktur, und wer 
alles welche ressourcen bearbeiten kann abhängen. Auch kombinationen 
davon können sinn machen. Eventuell kann man auch mit der momentanen 
Zeit und eventual consistency herumspielen. Da spielt dann auch noch 
eine Rolle, ob man konflikte bei änderungen erkennen will, oder nicht.

Für die Datenübertragung selbst würde ich weiterhin einfach JSON nehmen. 
Der Browser wird es beim senden gzip komprimieren.

Falls du eine Historie alter Einträge hast, könnte man auch einen diff 
zurückliefern. Es gibt da sogar diverse halbstandards, wie z.B. die HTTP 
PATCH methode, und anderes zeugs, aber meines wissens verwendet das 
keiner.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.