"Synchronisations-Theorie"
Andreas Korthaus
- programmiertechnik
Hallo!
Nachdem ich jetzt eine gesicherte Datenübertragung hinbekommen habe, habe ich das nächste Problem, mit dem Ablauf der Synchronisation an sich. Das Problem bei der Synchronisation mehrerer(>2) MySQL-Datenbanken besteht darin, das in 2 Datenbanken gleichzeitig neue Datensätze einfügt werden können, und wenn dazwischen keine Synchronisation erfolgt ist habe ich 2 gleiche IDs. Genauer beschrieben habe ich das hier: http://forum.de.selfhtml.org/archiv/2002/9/23871/#m132003
Sven Rautenberg hatte mich auf einen neue Möglichkeit aufmerksam gemacht.
Ich zitiere mal kurz aus dem Archiv (http://forum.de.selfhtml.org/archiv/2002/9/23871/#m132052):
Erkläre eine Datenbank, die dauerhaft erreichbar ist, zur Master-Datenbank. Zu dieser Datenbank werden alle extern eingegebenen Daten hochgeladen, und sie hat im Zweifel die einzig gültigen Daten.
Um das Gehampel mit zwei ID-Feldern zu vermeiden, könntest du auch ein ID-Feld und ein Herkunftsfeld definieren. Das Herkunftsfeld definiert, welche dezentrale Datenbank zur Eingabe verwendet wurde. Wenn der Datensatz zur zentralen Datenbank hochgeladen wird, wird das Herkunftsfeld geändert und eine neue ID vergeben. Die Änderung wird dann zurückgesendet, bzw. generell komplett verteilt.
Mit diesem System kannst du anhand der Herkunfts-ID sehen, ob der Datensatz schon zentral gespeichert wurde.
soweit so gut. Das war auch wirklich praktisch, hat nur einen kleinen Haken:
Wenn ich eine Client-DB mit der Master-DB synchronisiere, mache ich das wie folgt:
1. Ermittlung des letzten Synchronisations-Zeitpunktes(wird geloggt)
2. Ermittlung aller neuen Datensätze anhand der HerkunftsID (alle Inserts nach der letzten Synchronisation haben noch die ursprüngliche vom Client vergeben HerkunftsID)
3. entsprechend Generierung von INSERT-Statements
4. Ermittlung alle Aktualisierungen(Updates), Ermittlung anhand der HerkunftsID(Wenn Datensatz schon älter aber geändert wurde hat er bereits eine HerkunftsID vom Master) _und_ des Timstamps
5. entsprechend Generierung von UPDATE-Statements
6. Übertragung der Daten auf den Master
7. generierte SQL-Statements ausführen
8. ?
-- hier komme ich nicht weiter. --
Das Problem besteht darin, die auf dem Client nicht vorhandenen Datensätze herauszufinden. OK, man kann auch hier den Zeitpunkt der letzten Synchronisation ermitteln (da komme ich wohl nicht drum herum wegen der Updates), aber wie unterscheide ich zwischen Insert und Update? Woher weiß ich ob der Datensatz jetzt neu angelegt wurde und noch nicht auf dem Client vorhanden ist, oder ob er lediglich geändert wurde? Ich kann ja leider nicht mit einem Insert einen vorhandenen Datensatz mit gleicher ID überschreiben!
Hat jemand ne Idee wie ich das Problem lösen kann? Ich möchte hierbei nicht in die eigentliche Anwendung(d.h. die Anwendung die synchronisiert werden soll) eingreifen, d.h. deren INSERT-Statements verändern. Gibt es eine Möglichkeit in MySQL einen automatischen Timestamp für die Erstellung des Datensatzes einzufügen? Sowas der Art den Standardwert vom 2. Timestamp auf NOW() setzen(geht leider nicht)?
Sonst fiele mit nur ein _noch ein weiteres_ Feld in jede Tabelle einzufügen, und zwar mit einem Synchronisations-Status, standardmäßig auf 0, nach der Synchronisation auf 1 gesetzt.
Dafür behält das HerkunftID Feld für immer seine ID. Jetzt kann ich auf dem Client anhand des Statusfeldes sehen, ob der Datensatz bereits synchronisiert wurde, und auf dem Master kann ich an dem HerkunftsID Feld sehen, ob der Datensatz schon auf dem Client vorhanden ist.
Aber dann hätte ich schon 2 extra Felder, hat vielleicht jemand ne bessere Idee?
Viele Grüße und danke fürs Lesen ;-)
Andreas
Hallo,
Um das Gehampel mit zwei ID-Feldern zu vermeiden, könntest du auch ein ID-Feld und ein Herkunftsfeld definieren. Das Herkunftsfeld definiert, welche dezentrale Datenbank zur Eingabe verwendet wurde. Wenn der Datensatz zur zentralen Datenbank hochgeladen wird, wird das Herkunftsfeld geändert und eine neue ID vergeben. Die Änderung wird dann zurückgesendet, bzw. generell komplett verteilt.
Wobei ich mich frage, was das bringen soll, wenn die Id's und das Herkunftsfeld geändert wird. Es geht doch einzig und allein darum, daß ein Datensatz eindeutig identifiziert werden kann, wobei verschiedene, ich nehm jetzt mal ein altmodisches Wort dafür, 'Nummerngeneratoren' für die ID verwendet werden. Und zwar für jede Datenbank ein eigener, wobei das Herkunftsfeld festlegt, welche Datenbank das jetzt war.
So, und nun wieder zum eigentlichen Problem.
Ich habe vor kurzem noch an einem Synchronisationsproblem gearbeitet, dessen Lösung wir irgendwan vor einem Jahr oder so diskutiert haben. Im Archiv wirst Du sicherlich noch fündig. Dabei haeb ich jedoch für jeden Datensatz in den dezentralen Datenbanken zwei ID's gepflegt, eine lokale ID und eine Server-ID. Ein Grund dafür war eigentlich,daß die dezentralen Datenbanken viel weniger Daten speichern mußten, da sie nur für das Remotesystem relevante Daten vom Server bekamen. Aber das ist eine andere Geschichte.
Egal, nehmen wir einmal an, wir verwenden ID + Herkunft für die Identifikation.
Ich verwende zwei Methoden, um geänderte Daten festzustellen. Am zentralen Server wird die Timestamp verwendet, und die Remotedatenbanken verwenden ein Änderungsflag. Der Grund dafür ist, daß ich mich nicht mit den wahrscheinlcih sicherlich vorhandenen Unterschieden der Systemzeiten auseinandersetzen will.
So, wie läuft nun _meine_ Synchronisation ab:
1.) Grundsätzlich startet nur das Remotesystem die Synchronisation.
2.) Hier werden zuerst alle Datensätze der zu synchronisierenden Tabellen ermittelt, wobei unerheblich ist, ob es neue oder modifizierte Datensätze sind.
3.) diese Daten werden in ein neutrales Format (Text-Dateien) gebracht und an den Server übertragen.
4.) Als Meta-Information wird noch die Remotehost-ID und der Zeitpunkt der letzten Synchronisation übertragen.
5.) Am Server wird zuerst einmal der aktuelle Timestamp ermittelt. Dieser Wert dient einerseits dazu, daß nur Daten, die bis zu diesem Wert in der Datenbank sind berücksichtigt werden, zum anderen wird er auch zurück an das Remotesystem übertragen, wo für die nächste Synchronisation als 'letzter Synchronisationszeitpunkt' abgelegt wird.
6.) dann wird jeder übertragene Datensatz des Remotesyystems eingepflegt. Das passiert so, daß zuerst anhand der ID (+Herkunftskennung) geprüft wird, ob er schon vrhanden ist. Wenn nicht, dann wird ein Insert geamcht, ansonst ein Update. Für die Bestätigung werden nun für jeden Datensatz eine Rückmeldung generiert, die praktisch dem Übertragungs-Datensatzformat entspricht.
7.) Ist das erledigt, werden am Server nun alle Datensätze ausgelesen, die zwischen dem letzten Synchronisationstzeitpunkt (das ist der vom Remotesystem übertragene Zeitpunkt) und dem unter 5.) ermittelten Timestamp geändert wurden. Diese Daten werde auch in das Übertragungs-Text-Format übergeführt.
8.) die so gesammelten Daten werden nun an das Remotesystem, gemeinsam mit dem unter 5.) ermittelten Timestamps übertragen.
9.) Am Remotesystem wird nun analog zum Server die Daten Satz für Satz in die Datenbank eingepflegt. Dabei wird wieder überprüft, ob es den Datensatz schon gibt und entsprechend ein Insert oder Updatestatement generiert.
10.) der Timestamp wird am Remotesystem lkal abgelegt, um bei der nächsten Synchronisation wiederverwendet zu werden.
Einige Anmerkungen zum Übertragungsformat. Ich habe, da mir am Remotesystem kein XML-Parser zur Verfügung steht, und weil bei der mir zur Verfügung stehenden Übertragungsgeschwindigkeit XML etwas zu viel Overhead hat ein einfaches TextFormat gewählt. Eine solche Übertragungsdatei siehtvielleicht so aus:
[TABELLENNAME]
ID:4711
HERKUNFT:123
NAME:ABCDEF
WERT:1234
MEMO:xyzdsdskdkjdsk
MODFLAG:1
[EOR]
ID:4712
HERKUNFT:123
NAME:ABCDEF
WERT:1234
MEMO:xyzdsdskdkjdsk
MODFLAG:1
[EOR]
...
[ANDERE_TABELLE]
ID:815
HERKUNFT:123
...
MODFLAG:1
[EOR]
[END_OF_FILE]
Als Antwort kommt dann vielleicht:
[TABELLENNAME]
ID:4711
HERKUNFT:123
MODFLAG:0
[EOR]
ID:4712
HERKUNFT:123
MODFLAG:2
[EOR]
ID:7773232
HERKUNFT:1
NAME:HDDJKHK
WERT:12323
MEMO:xyzdsdskdkjdsk
MODFLAG:0
[EOR]
[ANDERE_TABELLE]
ID:815
HERKUNFT:123
MODFLAG:0
[EOR]
[END_OF_DATA]
Mit dem Feld MODFLAG in der Antwort kann ich steuern, was lokal passieren soll. Wenn MODFLAG z.B. Null ist, dann ist alles gut gegangen, ich kann lokal bei diesem Datensatz das Flag auch zurücksetzen. Wenn es nicht Null ist, dann enthält es einen vereinbarten Fehlercode, auf dem halt irgenwie reagiert werden sollte. Der Datensatz muß in jedem Fall bei der nächsten Synchronisation wieder übertragen werden. Auhc bei einem Konfliktmanagment können diese Rückmeldungen wertvoll sein.
Die einzige Einschränkung m.E., die dieses Fromat, außer daß es nicht hip ist, hat, ist, daß es keine Tabelle geben darf, die EOR oder END_OF_DATA heißt;-)
Das Erzeigen und Verarbeiten läßt sich mit einem einfachen Zustandsautomaten lösen und ist eigentlich beliebig ausbaubar.
Außerdem ist der Mechanismus für die Übertragung per HTTP geeignet, wobei genau das eine der Absichten war.
So ich hoffe, das so halbwegs auf die Reihe gebracht zu haben, ohne vollkommen unverständlich zu sein. Aber wenn Du noch Fragen hast, weißt Du ja, wo Du mich findest;-)
Grüße
Klaus
Hallo!
Vorab, ich habe versucht das so zu entwickeln, das man es in bestehende Systeme einbinden kann, ohne in Abfragen eingreifen zu müssen. Und ich denke ich bin auf dem richtigen Weg das das auch gelingen sollte.
Um das Gehampel mit zwei ID-Feldern zu vermeiden, könntest du auch ein ID-Feld und ein Herkunftsfeld definieren. Das Herkunftsfeld definiert, welche dezentrale Datenbank zur Eingabe verwendet wurde. Wenn der Datensatz zur zentralen Datenbank hochgeladen wird, wird das Herkunftsfeld geändert und eine neue ID vergeben. Die Änderung wird dann zurückgesendet, bzw. generell komplett verteilt.
Wobei ich mich frage, was das bringen soll, wenn die Id's und das Herkunftsfeld geändert wird. Es geht doch einzig und allein darum, daß ein Datensatz eindeutig identifiziert werden kann, wobei verschiedene, ich nehm jetzt mal ein altmodisches Wort dafür, 'Nummerngeneratoren' für die ID verwendet werden. Und zwar für jede Datenbank ein eigener, wobei das Herkunftsfeld festlegt, welche Datenbank das jetzt war.
Ja, aber da bekome ich mit meinem obigen Vorhaben probleme, ich müsste sämtliche Abfragen, Links, Parameter... verändern, da ich keien eindeutige ID mehr habe. Wenn aber alle Datensätze überall eindeutig über eine Id definiert sind, wird das erheblich einfacher, und wenn dann noch die Tabellen komplett gleich sind, dann befindet man sich im 7. Synchronistaions-Himmel, wobei ich weiß das man das eigentlich von eienr anderen Seite her angehen sollte, aber ich weiß schon was ich tue wenn ich das für eine Anwendung implementiere.
So, und nun wieder zum eigentlichen Problem.
Ich habe vor kurzem noch an einem Synchronisationsproblem gearbeitet, dessen Lösung wir irgendwan vor einem Jahr oder so diskutiert haben. Im Archiv wirst Du sicherlich noch fündig. Dabei haeb ich jedoch für jeden Datensatz in den dezentralen Datenbanken zwei ID's gepflegt, eine lokale ID und eine Server-ID. Ein Grund dafür war eigentlich,daß die dezentralen Datenbanken viel weniger Daten speichern mußten, da sie nur für das Remotesystem relevante Daten vom Server bekamen. Aber das ist eine andere Geschichte.
Egal, nehmen wir einmal an, wir verwenden ID + Herkunft für die Identifikation.
Ich verwende zwei Methoden, um geänderte Daten festzustellen. Am zentralen Server wird die Timestamp verwendet, und die Remotedatenbanken verwenden ein Änderungsflag.
Gut, das heißt Du hast verschieden Tabellen auf dem Client und dem Master, oder zumindest entsprechende verschiedene Abfragen in der Anwendung, oder? Das will ich nicht!
Der Grund dafür ist, daß ich mich nicht mit den wahrscheinlcih sicherlich vorhandenen Unterschieden der Systemzeiten auseinandersetzen will.
Wieso? Das ist doch das einfachste! Du loggst auf beiden Systemen nicht eine Zeit sondern die jeweils eigene System-Zeit und ziehst die dann bei Vergleichen heran!
So, wie läuft nun _meine_ Synchronisation ab:
1.) Grundsätzlich startet nur das Remotesystem die Synchronisation.
bei mir auch
2.) Hier werden zuerst alle Datensätze der zu synchronisierenden Tabellen ermittelt, wobei unerheblich ist, ob es neue oder modifizierte Datensätze sind.
genauso bei mir
3.) diese Daten werden in ein neutrales Format (Text-Dateien) gebracht und an den Server übertragen.
vielleicht nicht neutral, aber SQL-Statements finde ich besser
4.) Als Meta-Information wird noch die Remotehost-ID und der Zeitpunkt der letzten Synchronisation übertragen.
der Remote-Host wird auch übertragen, der letzte Sync Timestamp wird aber aus der jeweils eigenen speziellen sync-Tabelle ausgelesen, dem client entsprechend
5.) Am Server wird zuerst einmal der aktuelle Timestamp ermittelt. Dieser Wert dient einerseits dazu, daß nur Daten, die bis zu diesem Wert in der Datenbank sind berücksichtigt werden, zum anderen wird er auch zurück an das Remotesystem übertragen, wo für die nächste Synchronisation als 'letzter Synchronisationszeitpunkt' abgelegt wird.
ich muß gestehen, das meine Timestamps nicht immer 100% gleich sind, sollt eich vielleicht mal drüber nachdenken.
6.) dann wird jeder übertragene Datensatz des Remotesyystems eingepflegt. Das passiert so, daß zuerst anhand der ID (+Herkunftskennung) geprüft wird, ob er schon vrhanden ist. Wenn nicht, dann wird ein Insert geamcht, ansonst ein Update. Für die Bestätigung werden nun für jeden Datensatz eine Rückmeldung generiert, die praktisch dem Übertragungs-Datensatzformat entspricht.
Das wird bei mir halt schon auf dem Client system ermittelt und entsprechend vorher generiert und dann auf dem Master ausgeführt.
7.) Ist das erledigt, werden am Server nun alle Datensätze ausgelesen, die zwischen dem letzten Synchronisationstzeitpunkt (das ist der vom Remotesystem übertragene Zeitpunkt) und dem unter 5.) ermittelten Timestamp geändert wurden. Diese Daten werde auch in das Übertragungs-Text-Format übergeführt.
Das habe ich auch so vor, halt mit der unterscheidung ob Update oder Insert, anhand einer StatusID, odr Flag oder wie auch immer Du das nennst, und der HerkuunftsID und dem Timestamp. Aus den Daten kann ich schon vor der Übertragung ermittlen, was für ein Statement ich generieren muß.
8.) die so gesammelten Daten werden nun an das Remotesystem, gemeinsam mit dem unter 5.) ermittelten Timestamps übertragen.
9.) Am Remotesystem wird nun analog zum Server die Daten Satz für Satz in die Datenbank eingepflegt. Dabei wird wieder überprüft, ob es den Datensatz schon gibt und entsprechend ein Insert oder Updatestatement generiert.
10.) der Timestamp wird am Remotesystem lkal abgelegt, um bei der nächsten Synchronisation wiederverwendet zu werden.
Einige Anmerkungen zum Übertragungsformat. Ich habe, da mir am Remotesystem kein XML-Parser zur Verfügung steht, und weil bei der mir zur Verfügung stehenden Übertragungsgeschwindigkeit XML etwas zu viel Overhead hat ein einfaches TextFormat gewählt. Eine solche Übertragungsdatei siehtvielleicht so aus:
[TABELLENNAME]
ID:4711
HERKUNFT:123
NAME:ABCDEF
WERT:1234
MEMO:xyzdsdskdkjdsk
MODFLAG:1
[EOR]
ID:4712
HERKUNFT:123
NAME:ABCDEF
WERT:1234
MEMO:xyzdsdskdkjdsk
MODFLAG:1
[EOR]
...
Warum hast Du kein CSV-Format gewählt?
Also ich mache das ganz anders, ich generiere auf dem Remote-Syestem Insert- und Update-Statements, die ich urlencode und mit curl an den Master schicke, dann mit PHP an die Standardeingabe für das mysql-Kommandozeilen-Tool übergebe. Das funktioniert sehr gut und ist darüberhinaus sehr schnell, wobei das Nadelöhr bei mir eher in der Übertragungszeit(trotz DSL) liegt, ich habe mit 120KB Daten gestestet, das dauert schon 10 Sekunden, vom Starten von Curl bis zur Erfolgsmeldung das die Daten am Server angekommen sind, sonst mache ich nichts!
Was mir noch gar nicht gut gefällt, ich schreibe die Inserts ohne ID in die Master-Datenbank, damit die hier "globale" ID bekommen. Um diese ID wieder zurückzuermitteln, mache ich das zur Zeit so, das ich die Datensätze (alle die neuer sind als der Startzeitpunkt der Synchronisation)komplett mit mysqldump auslese und wieder zurückübertrage, also extremst viel overhead, das sollte ich vielleicht mal ändern.
Mit dem Feld MODFLAG in der Antwort kann ich steuern, was lokal passieren soll. Wenn MODFLAG z.B. Null ist, dann ist alles gut gegangen, ich kann lokal bei diesem Datensatz das Flag auch zurücksetzen. Wenn es nicht Null ist, dann enthält es einen vereinbarten Fehlercode, auf dem halt irgenwie reagiert werden sollte. Der Datensatz muß in jedem Fall bei der nächsten Synchronisation wieder übertragen werden. Auch bei einem Konfliktmanagment können diese Rückmeldungen wertvoll sein.
Das Erzeigen und Verarbeiten läßt sich mit einem einfachen Zustandsautomaten lösen und ist eigentlich beliebig ausbaubar.
Sowas brauche ich auch noch, aber erstmal soll die Synchronisation so funktionieren, mal gucken wie ich das am besten integrieren kann.
So ich hoffe, das so halbwegs auf die Reihe gebracht zu haben, ohne vollkommen unverständlich zu sein. Aber wenn Du noch Fragen hast, weißt Du ja, wo Du mich findest;-)
Vielen Dank! Ich habe zur Zeit einen einfachen Synchronisationsmechanismus laufen, der seeehr einfach ist, aber leider etwas unsicher, denn er benötigt einen offenen mySQL-Port und wird unverschlüsselt quer durch das Internet geleitet. Die Variante über http(s) ist doch "etwas" komplizierter als ich es zu hoffen gewagt hatte! Aber das hätte ich schon locker geschafft, das was die ganze Sache wirklich kompliziert macht ist die von mir angestrebte "Modularität", also das ich diesen Mechansismus sehr leicht über andere Anwendungen drüberegen kann, egal was für Tabellen, egal was für Spaltennamen...
Jedenfalls vielen Dank für Deine Hilfe!
Viele Grüße
Andreas
Hallo,
Vorab, ich habe versucht das so zu entwickeln, das man es in bestehende Systeme einbinden kann, ohne in Abfragen eingreifen zu müssen. Und ich denke ich bin auf dem richtigen Weg das das auch gelingen sollte.
Und ich habe die Synchronisation zu einem BEstehenden Single-Db-System dazu entwickelt. Auf den Remotesystemen hatte ich Spielraum.
BTW: deshalb hatte ich auhc zwei ID-Felder bei den Remotesystemen.
Ja, aber da bekome ich mit meinem obigen Vorhaben probleme, ich müsste sämtliche Abfragen, Links, Parameter... verändern, da ich keien eindeutige ID mehr habe. Wenn aber alle Datensätze überall eindeutig über eine Id definiert sind, wird das erheblich einfacher, und wenn dann noch die Tabellen komplett gleich sind, dann befindet man sich im 7. Synchronistaions-Himmel, wobei ich weiß das man das eigentlich von eienr anderen Seite her angehen sollte, aber ich weiß schon was ich tue wenn ich das für eine Anwendung implementiere.
Nur... Wenn Du Beziehungen zwischen den Tabellen hast, mußt Du diese ja immer wieder korrigieren. D.h. Wenn Du die Id umschreibst, müssen, alle Datensätze anderer Tabellen, die sich darauf beziehen, entsprechend geändert werden. Das bedeute wesentlcih mehr Aufwand bei dr Synchronisationsschnittstelle. Das war auch die Schwachstelle bei der zwei-ID-Lösung. Die nächste zentrale Datenbank wird eine Herkunfts-ID aufweisen.
Vielleicht trifft Dich heute dieses Problem noch nicht, spätestens wenn Du mehrere Tabellen synchronisierst, die miteinander in Bezug stehen, wird es haarig.
Ich verwende zwei Methoden, um geänderte Daten festzustellen. Am zentralen Server wird die Timestamp verwendet, und die Remotedatenbanken verwenden ein Änderungsflag.
Gut, das heißt Du hast verschieden Tabellen auf dem Client und dem Master, oder zumindest entsprechende verschiedene Abfragen in der Anwendung, oder? Das will ich nicht!
Ja, wie gesagt, ich hatte Spielraum.
Der Grund dafür ist, daß ich mich nicht mit den wahrscheinlcih sicherlich vorhandenen Unterschieden der Systemzeiten auseinandersetzen will.
Wieso? Das ist doch das einfachste! Du loggst auf beiden Systemen nicht eine Zeit sondern die jeweils eigene System-Zeit und ziehst die dann bei Vergleichen heran!
Und schon wird's kompliziert. Welche Zeit bestimmt Deinen letzten Synchronisationszeitpunkt? Die der zentralen Datenbank, oder die des Remotesystems? oder merkst Du Dir beide Zeiten.
Naja, eine Lösung gäbe es ja dafür, XNTP. Das wäre sowieso das beste, allerdings mußt Du dann auch sicher sein, daß der immer funktioniert. Ich hatte anfangs schon Problem, wenn der Rechner auf dem die Sync-Engine läuft eine andere Zeit gegenüber dem Datenbanksystem hat.
3.) diese Daten werden in ein neutrales Format (Text-Dateien) gebracht und an den Server übertragen.
vielleicht nicht neutral, aber SQL-Statements finde ich besser
Das bedeutet aber, daß eines der Systeme etwas über das andere wissen muß. Ich habe es dagegen so ausgelegt, daß immer nur das System, auf dem der aktuelle Vorgang läuft, seine eigene Datenbank kennen muß.
4.) Als Meta-Information wird noch die Remotehost-ID und der Zeitpunkt der letzten Synchronisation übertragen.
der Remote-Host wird auch übertragen, der letzte Sync Timestamp wird aber aus der jeweils eigenen speziellen sync-Tabelle ausgelesen, dem client entsprechend
Ich habe es vorgezogen, daß das Remotesystem besser alles über den aktuellen Zustanad weiß, und daß das dem Zentralsystem ziemlich egal sien kann. Im zweifelsfall wurde die Remotedatenbank einfach durch einenen Dump neu angelegt, wobei dann dort auch der Sync-Timestamp eingetragen wurde.
5.) Am Server wird zuerst einmal der aktuelle Timestamp ermittelt. Dieser Wert dient einerseits dazu, daß nur Daten, die bis zu diesem Wert in der Datenbank sind berücksichtigt werden, zum anderen wird er auch zurück an das Remotesystem übertragen, wo für die nächste Synchronisation als 'letzter Synchronisationszeitpunkt' abgelegt wird.
ich muß gestehen, das meine Timestamps nicht immer 100% gleich sind, sollt eich vielleicht mal drüber nachdenken.
Wie gesagt, das Remotesystem sollte von sich alles wissen. Daß ich den aktuellen Timestamp quasi als oberer Grenze eingezogen habe, liegt daran, daß bei mir die Synchronisation jederzeit stattfinden konnte, meist wirklich auch dann, wenn auf dem zentralsystem Datenmanipulationen durchgeführt werden, in der Geschäftszeit sozusagen.
6.) dann wird jeder übertragene Datensatz des Remotesyystems eingepflegt. Das passiert so, daß zuerst anhand der ID (+Herkunftskennung) geprüft wird, ob er schon vrhanden ist. Wenn nicht, dann wird ein Insert geamcht, ansonst ein Update. Für die Bestätigung werden nun für jeden Datensatz eine Rückmeldung generiert, die praktisch dem Übertragungs-Datensatzformat entspricht.
Das wird bei mir halt schon auf dem Client system ermittelt und entsprechend vorher generiert und dann auf dem Master ausgeführt.
Wobei, wie ich schon erwähnte, die Clientseite einiges über die Zentrale Datenbank wissen muß. Konfilktmanagment wird dadurch enorm erschwert.
7.) Ist das erledigt, werden am Server nun alle Datensätze ausgelesen, die zwischen dem letzten Synchronisationstzeitpunkt (das ist der vom Remotesystem übertragene Zeitpunkt) und dem unter 5.) ermittelten Timestamp geändert wurden. Diese Daten werde auch in das Übertragungs-Text-Format übergeführt.
Das habe ich auch so vor, halt mit der unterscheidung ob Update oder Insert, anhand einer StatusID, odr Flag oder wie auch immer Du das nennst, und der HerkuunftsID und dem Timestamp. Aus den Daten kann ich schon vor der Übertragung ermittlen, was für ein Statement ich generieren muß.
Hier wird es wieder umgekehrt. Das Zentrale System muß viel über das Remotesystem wissen, auhc das empfinde ich als enormen Nachteil.
Warum hast Du kein CSV-Format gewählt?
Weil das unflexibler ist. Vielleicht soll ich noch etwas wieter ausholen. Ich habe bewußt eingeplant, daß sich die Datenstrukturen auf den Systemen unterscheiden können. So war es von haus aus klar, daß die Remotesysteme nur mit einem Subset an Daten auskommen müssen. Es war sogar so, daß sie nicht einmal die selbe Tabellenstruktur hatten. Außerdem wurde im Laufe der Zeit am Remotesystem Erweiterungen durchgeführt, die ich natürlcih auch abdecken wollte. Dabei kamen bei beiden Systemen sowieso unterschiedliche DBMS zum Einsatz.
Also ich mache das ganz anders, ich generiere auf dem Remote-Syestem Insert- und Update-Statements, die ich urlencode und mit curl an den Master schicke, dann mit PHP an die Standardeingabe für das mysql-Kommandozeilen-Tool übergebe. Das funktioniert sehr gut und ist darüberhinaus sehr schnell, wobei das Nadelöhr bei mir eher in der Übertragungszeit(trotz DSL) liegt, ich habe mit 120KB Daten gestestet, das dauert schon 10 Sekunden, vom Starten von Curl bis zur Erfolgsmeldung das die Daten am Server angekommen sind, sonst mache ich nichts!
Wobei ich denke, daß die Statements vom Volumen her um nichts kleiner sind als 'meine' Daten, eher etwas mehr. Noch etwas, leere Felder werden bei mir natürlich nicht übertragen, warum auch.
Was mir noch gar nicht gut gefällt, ich schreibe die Inserts ohne ID in die Master-Datenbank, damit die hier "globale" ID bekommen. Um diese ID wieder zurückzuermitteln, mache ich das zur Zeit so, das ich die Datensätze (alle die neuer sind als der Startzeitpunkt der Synchronisation)komplett mit mysqldump auslese und wieder zurückübertrage, also extremst viel overhead, das sollte ich vielleicht mal ändern.
Ja, deshalb siehe meine Lösung, da wird eigentlich nur das notwendigst geschickt, ohne zuviel Flexibilität zu verlieren.
Sowas brauche ich auch noch, aber erstmal soll die Synchronisation so funktionieren, mal gucken wie ich das am besten integrieren kann.
Bei so einem Vorhaben solltest Du wirklich alles zumindest woerit überlegen, daß Du Dir mit der Lösung nicht zu viele Wege verbbaust. Ich bin zwar ans sich auch nicht dafür, gleich von Anfang an alle möglichen Eventualitäten einzubauen, nur das grundlegende Modell sollte robust genug sein, auch bei Erweiterungen noch zu funktionieren.
Ich denke zwar nicht, dßa meine Lösung unbedingt die beste ist, vor allem da ich doch einiges an Rahmenbedingungen hatte, die andere Wege von vorn herein ausgeschlossen haben. Trotzdem denke ich, daß da einiges auhc für Dein vorhaben drin ist. Wir werden ja sehen, was Du da letztendlich ausbrütest;-)
Grüße
Klaus
Hallo!
Und ich habe die Synchronisation zu einem BEstehenden Single-Db-System dazu entwickelt. Auf den Remotesystemen hatte ich Spielraum.
Übrigens soll meine Synchronisation mit mehreren Systemen funktionieren, zw. 2-10. Die Anwendung auf allen Systemen ist dieselbe, zumindest die Datenbank.
Nur... Wenn Du Beziehungen zwischen den Tabellen hast, mußt Du diese ja immer wieder korrigieren. D.h. Wenn Du die Id umschreibst, müssen, alle Datensätze anderer Tabellen, die sich darauf beziehen, entsprechend geändert werden. Das bedeute wesentlcih mehr Aufwand bei dr Synchronisationsschnittstelle. Das war auch die Schwachstelle bei der zwei-ID-Lösung. Die nächste zentrale Datenbank wird eine Herkunfts-ID aufweisen.
OHHHHH! Bei der Anwendung die ich gerade entwickle ist das zwar nicht so, aber bei einer anderen... Da hab ich ja überhaupt noch nicht dran gedacht! Muß ich jetzt schon wieder alles umschmeißen? Och nö....
Vielleicht trifft Dich heute dieses Problem noch nicht, spätestens wenn Du mehrere Tabellen synchronisierst, die miteinander in Bezug stehen, wird es haarig.
Auweia, da muß ich mir doch glatt was neues überlegen. Da kommt aber wieder eine andere Variante ins Spiel, die ich von Philipp Hasenfratz habe und von der mich Sven Rautenberg nur mit Mühe abbringen konnte:
Ich teile den "ID-Raum" untern den Systemen auf, z.B. System 1 hat IDs von 1.000.000.000 bis 1.999.999.999 usw.
Dann müßte ich die IDs nicht nachträglich verändern. Ich sträube mich aber sehr dagagen, ein komplettes Projekt komplett umzubauen, nämlich dann wenn keien eindeutige ID mehr gegeben ist. Wie gesagt, alle Parameter, Links, Formulare, Header-Weiterleitungen, SELECTS, INSERTS, UPDATES... und bestimmt einiges was ich vergessen werde ;-) Kann man das vielleicht mit Foreign Keys lösen? Ich hatte eh vor erst alle Datensätze zu löschen und zu überschreiben!
Wieso? Das ist doch das einfachste! Du loggst auf beiden Systemen nicht eine Zeit sondern die jeweils eigene System-Zeit und ziehst die dann bei Vergleichen heran!
Und schon wird's kompliziert. Welche Zeit bestimmt Deinen letzten Synchronisationszeitpunkt? Die der zentralen Datenbank, oder die des Remotesystems? oder merkst Du Dir beide Zeiten.
Ich merke mir beide Zeiten, alles andere ist ungenau, egal was Du Dir ausdenkst, es ist und bleibt eine "Stolperfalle".
Naja, eine Lösung gäbe es ja dafür, XNTP. Das wäre sowieso das beste, allerdings mußt Du dann auch sicher sein, daß der immer funktioniert. Ich hatte anfangs schon Problem, wenn der Rechner auf dem die Sync-Engine läuft eine andere Zeit gegenüber dem Datenbanksystem hat.
Das läuft bei mir immer auf jeweils einer Maschine.
vielleicht nicht neutral, aber SQL-Statements finde ich besser
Das bedeutet aber, daß eines der Systeme etwas über das andere wissen muß. Ich habe es dagegen so ausgelegt, daß immer nur das System, auf dem der aktuelle Vorgang läuft, seine eigene Datenbank kennen muß.
OK, vermutlich hast Du das ganze auf einem etwas höheren Level gemacht, ich verwende rundrum MySQL und das wird auch so bleiben. Da die Anwendung auf allen Systemen dieselbe ist, ist auch dei komplette Datenstruktur gleich, daher reicht das Wissen um die eigene Datenstruktur vollkommen aus! Änderungen müssen auf allen Systemen durchgeführt werden.
der Remote-Host wird auch übertragen, der letzte Sync Timestamp wird aber aus der jeweils eigenen speziellen sync-Tabelle ausgelesen, dem client entsprechend
Ich habe es vorgezogen, daß das Remotesystem besser alles über den aktuellen Zustanad weiß, und daß das dem Zentralsystem ziemlich egal sien kann. Im zweifelsfall wurde die Remotedatenbank einfach durch einenen Dump neu angelegt, wobei dann dort auch der Sync-Timestamp eingetragen wurde.
Da bei mir die Datenstruktur überall gleich ist kann ich auch überall die Daten mit einem Dump ersetzen, bis auf die Kleinigkeit das die zu synchronisieren Tabellen ein Feld mit HerkunftsID haben, der den eigenen Standort als Standardwert hat. Dafür schreibe ich aber ein config-Script, welches solche Dinge eben einstellt.
Hier wird es wieder umgekehrt. Das Zentrale System muß viel über das Remotesystem wissen, auhc das empfinde ich als enormen Nachteil.
Wie gesagt, wenn die Datenstruktur gleich ist(auch Tabellennamen, Spaltennamen, Formate, Inhalte), dann reicht das Wissen über die eigene DB. Das habe ich extra gemacht um diese Probleme zu umgehen.
Wobei ich denke, daß die Statements vom Volumen her um nichts kleiner sind als 'meine' Daten, eher etwas mehr. Noch etwas, leere Felder werden bei mir natürlich nicht übertragen, warum auch.
Bei Updates genauso, aber die Inserts sind bei mir kürzer, alleine aufgrund der Schreibweise:
INSERT INTO tabelle (spalte1,spalte2) VALUES
(12,34),
(56,78),
(90,12),
...
Aber Du hast Recht, daran soll es nicht liegen, vermutlich läßt sich Deine Version dafür besser komprimieren, und schon ist es egal! Hast Du das eigentlich auch implementiert, eine Komprimierung?
Hast Du auch eine Verschlüsselung eingesetzt?
Ja, deshalb siehe meine Lösung, da wird eigentlich nur das notwendigst geschickt, ohne zuviel Flexibilität zu verlieren.
Das stimmt schon, ich hatte nur Angst das sowas zu langsam wird, da ich auf einem System an Laufzeiten gebunden bin, wenn dann noch die langen Übertragungszeiten dazu kommen... Wenn ich einmal mein Statements direkt im ersten Schritt noch während des Auslesens der Ursprungs-Datenbank generiere, und über das Kommandozeilen-tool einlese, geht das unheimlich schnell. Bei Deiner Variante brauch ich ja jedesmal erst ein SELECT um zu prüfen ob der Eintrag vorhanden, müßte dann in einer Schleife das Statement generieren und dann noch ein INSERT-Statement.
Wie machst Du das denn eigentlich mit dem Parsen? Wie bekommst Du die Datensätze für eine Tabelle in einen Array? Ich meine wo "splittest" Du? OK, danach kannst Du bei [EOR] splitten, und dann jeweils bei :, vermutlich schreibst Du das dann jeweils als key-value Paar in einen Array, nur was machst Du wenn in den Daten mal ein ":" vorkommt? So Probleme habe ich alle nicht!
[TABELLENNAME]
ID:4711
HERKUNFT:123
NAME:ABCDEF
WERT:1234
MEMO:xyzdsdskdkjdsk
MODFLAG:1
[EOR]
ID:4712
HERKUNFT:123
NAME:ABCDEF
WERT:1234
MEMO:xyzdsdskdkjdsk
MODFLAG:1
[EOR]
...
[ANDERE_TABELLE]
ID:815
HERKUNFT:123
...
Ich denke zwar nicht, dßa meine Lösung unbedingt die beste ist, vor allem da ich doch einiges an Rahmenbedingungen hatte, die andere Wege von vorn herein ausgeschlossen haben. Trotzdem denke ich, daß da einiges auhc für Dein vorhaben drin ist. Wir werden ja sehen, was Du da letztendlich ausbrütest;-)
Ja ich bin auch mal gespannt, vielen Dank für Deine Hilfe, vermutlich hast Du mich vor einem größeren Fehler bewahrt! Velen Dank!
Viele Grüße
Andreas
Hallo,
Auweia, da muß ich mir doch glatt was neues überlegen. Da kommt aber wieder eine andere Variante ins Spiel, die ich von Philipp Hasenfratz habe und von der mich Sven Rautenberg nur mit Mühe abbringen konnte:
Ich teile den "ID-Raum" untern den Systemen auf, z.B. System 1 hat IDs von 1.000.000.000 bis 1.999.999.999 usw.
Da hatte er sicher Recht, wobei zu bedenken ist, daß zwei Felder mit 32 Bit praktisch einem berechneten Feld mit 64 Bit ist. Allerdings muß man so viel beachten, vro allem die Möglichkeiten der Datenbank, daß auch ich glaube, daß es besser ist, mit zwei Feldern zu arbeiten.
Und autoincrement kannst Du afaik auch gleich vergessen. Das ist zu unflexibel für diese Art von Anwendungen.
Dann müßte ich die IDs nicht nachträglich verändern. Ich sträube mich aber sehr dagagen, ein komplettes Projekt komplett umzubauen, nämlich dann wenn keien eindeutige ID mehr gegeben ist. Wie gesagt, alle Parameter, Links, Formulare, Header-Weiterleitungen, SELECTS, INSERTS, UPDATES... und bestimmt einiges was ich vergessen werde ;-)
Naja besser ist es aber doch, sich beizeiten von einem mangelhaftem Konzept zu lösen, als es mit aller Gewalt in die Zukunft retten zu wollen. Meist kommt nur ein vielfaches an Arbeit raus. Naja, wenn man es bezahlt bekommt, wäre das ja eher ein Argument dafür *ggg*.
Kann man das vielleicht mit Foreign Keys lösen? Ich hatte eh vor erst alle Datensätze zu löschen und zu überschreiben!
Foreign-Keys haben mit den konsistenten Beziehungen der Daten in verschiedenen Tabellen zu tun, niicht mit der ID-Generierung. Die ID's müssen schon vorher festgelegt sein.
Und Löschen und Neuschreiben finde ich für wirklich gefährlich. Was, wenn aus irgendeinem Grunde das Insert nicht mehr funktioniert? Woher sollen dann die Daten rekonstruiert werden. Denke auch an unvorhergesehenes wie Stromausfälle und so weiter. Konsistenz ist für solche Sachen oberstes Gebot.
Naja, eine Lösung gäbe es ja dafür, XNTP. Das wäre sowieso das beste, allerdings mußt Du dann auch sicher sein, daß der immer funktioniert. Ich hatte anfangs schon Problem, wenn der Rechner auf dem die Sync-Engine läuft eine andere Zeit gegenüber dem Datenbanksystem hat.
Das läuft bei mir immer auf jeweils einer Maschine.
XNTP-Clients sollten alber dann auf allen laufen. BTW.: mit Tardis (weiß den Link momentan nicht) habe ich recht gute Erfahrungen, wenn es um XNTP unter NT/2000 geht.
»»» OK, vermutlich hast Du das ganze auf einem etwas höheren Level gemacht, ich verwende rundrum MySQL und das wird auch so bleiben. Da die Anwendung auf allen Systemen dieselbe ist, ist auch dei komplette Datenstruktur gleich, daher reicht das Wissen um die eigene Datenstruktur vollkommen aus! Änderungen müssen auf allen Systemen durchgeführt werden.
Nein ich meinte, daß es nicht nur die Struktur, sondern auch die Daten kennen muß. Wie sonst soll es entscheiden, ob Insert oder Update richtig sind? Für meinen Geschmack zuviel notwendiges Wissen. Außerdem entscheidet dann immer das eine System, was auf dem anderen passieren soll. Da entstehen imho zu viele Verflechtungen.
Aber Du hast Recht, daran soll es nicht liegen, vermutlich läßt sich Deine Version dafür besser komprimieren, und schon ist es egal! Hast Du das eigentlich auch implementiert, eine Komprimierung?
Nein, ich wollte mir das nicht antun und Zeit war auch keine dafür. Nach unseren Tests war der Verbindungsaufbau über das Modem sowieso länger (ca 25 sec) als der üblich Datentransfer (ca.10-20 sec). Der gesamte Abgleich dauert doch deutlich länger, da das Remotesystem relativ wenig Rechenleistung hat. Außerdem ist die DB-Performance dort bei Modifikationen nicht gerade weltrekordverdächtig.
Hast Du auch eine Verschlüsselung eingesetzt?
Ja, TripleDES für die Daten, aber kein SSL.
Das stimmt schon, ich hatte nur Angst das sowas zu langsam wird, da ich auf einem System an Laufzeiten gebunden bin, wenn dann noch die langen Übertragungszeiten dazu kommen... Wenn ich einmal mein Statements direkt im ersten Schritt noch während des Auslesens der Ursprungs-Datenbank generiere, und über das Kommandozeilen-tool einlese, geht das unheimlich schnell. Bei Deiner Variante brauch ich ja jedesmal erst ein SELECT um zu prüfen ob der Eintrag vorhanden, müßte dann in einer Schleife das Statement generieren und dann noch ein INSERT-Statement.
Es leben die Stored Procedures;-)
Ich muß gestehen, daß stored procedures, Trigger usw. das Leben für solche Sachen erheblich erleichtern, da Du bereits in der Datenbank vieles abbilden kannst, ohne ständig in irgendeiner Anwendung herumzuwurschteln. mySQL ist da nicht ganz so toll bestückt.
Wie machst Du das denn eigentlich mit dem Parsen? Wie bekommst Du die Datensätze für eine Tabelle in einen Array? Ich meine wo "splittest" Du? OK, danach kannst Du bei [EOR] splitten, und dann jeweils bei :, vermutlich schreibst Du das dann jeweils als key-value Paar in einen Array, nur was machst Du wenn in den Daten mal ein ":" vorkommt? So Probleme habe ich alle nicht!
----------------------------------------
my($tabelle,%daten);
foreach(@inputlines) {
chomp;
if(/^[EOR]$/) {
run_import_record($tabelle,%daten) if $tabelle;
%daten = ();
}
elsif(/^[(.+)]$/) {
$tabelle = $1;
}
else {
my($name,$wert) = split('\s*:\s*',$_,2);
$daten{$name}=$wert;
}
}
----------------------------------------
(In Perl (ungefähr), in C++ ist's etwas komplexer *g*)
Grüße
Klaus
Halihallo Klaus
Auweia, da muß ich mir doch glatt was neues überlegen. Da kommt aber wieder eine andere Variante ins Spiel, die ich von Philipp Hasenfratz habe und von der mich Sven Rautenberg nur mit Mühe abbringen konnte:
Ich teile den "ID-Raum" untern den Systemen auf, z.B. System 1 hat IDs von 1.000.000.000 bis 1.999.999.999 usw.
Da hatte er sicher Recht, wobei zu bedenken ist, daß zwei Felder mit 32 Bit praktisch einem berechneten Feld mit 64 Bit ist. Allerdings muß man so viel beachten, vro allem die Möglichkeiten der Datenbank, daß auch ich glaube, daß es besser ist, mit zwei Feldern zu arbeiten.
Warum zwei 32Bit? - Andreas hat keine 2^32 Datenbanken, glaub ich zumindest ;-)
Du brauchst ja nur ca. 8bit für die DatenbankID und den Rest für die ID der Records. Ja, mit zwei Feldern zu arbeiten wäre in der Tat viel besser, aber: dann hast du ein Feld DatenbankID und eine ID mit autoinc. Jeder Datensatz ist bezogen auf das System unique, aber dann müsste Andreas die DatenbankID immer noch in die SQL Abfragen einfügen => ARBEIT...
Und autoincrement kannst Du afaik auch gleich vergessen. Das ist zu unflexibel für diese Art von Anwendungen.
Ja, den müsste man selber implementieren. Klar, wenn man den ID Raum aufteilt, kommt man nicht darum herum; es sei denn man könnte den startindex im Tableheader festlegen.
Kann man das vielleicht mit Foreign Keys lösen? Ich hatte eh vor erst alle Datensätze zu löschen und zu überschreiben!
Foreign-Keys haben mit den konsistenten Beziehungen der Daten in verschiedenen Tabellen zu tun, niicht mit der ID-Generierung. Die ID's müssen schon vorher festgelegt sein.
Und Löschen und Neuschreiben finde ich für wirklich gefährlich. Was, wenn aus irgendeinem Grunde das Insert nicht mehr funktioniert? Woher sollen dann die Daten rekonstruiert werden. Denke auch an unvorhergesehenes wie Stromausfälle und so weiter. Konsistenz ist für solche Sachen oberstes Gebot.
Nun, bei der Synchronisation treten ja leider noch mehr Probleme auf: Was, wenn der Datenbestand auf einer DB ändert, noch während der Synchronisation? - In den meisten Fällen kann man das mit den Flags und Timestamps ja "unterbinden", aber 100% ist die Lösung auch nicht. Man müsste theoretisch während der Synchronisation die Table locken, bzw. wirklich jeden Datensatz hin und her schaufeln und alles "asynchron" (also immer senden/empfangen von einem Datensatz, nicht synchron: das ganze Packet hin und zurück) abarbeiten.
Viele Grüsse
Philipp
Hallo!
Du brauchst ja nur ca. 8bit für die DatenbankID und den Rest für die ID der Records. Ja, mit zwei Feldern zu arbeiten wäre in der Tat viel besser, aber: dann hast du ein Feld DatenbankID und eine ID mit autoinc. Jeder Datensatz ist bezogen auf das System unique, aber dann müsste Andreas die DatenbankID immer noch in die SQL Abfragen einfügen => ARBEIT...
Wie gesagt, es sind nicht nur die Abfragen, was mir noch eingefallen ist - das Problem besteht ja lediglich bei Verknüpfungen. Und wenn ich die Variante mit den 2 Ids verwende, dann müßten ja auch alle Verknüpfungen über 2 IDs gehen, Also müßte ivch auch noch die ganzen betroffenen Tabellen umstellen, bekäme große Probleme mit aktuellen Daten... das ist doch alles Mist. Wenn man das von vornherein dafür entwickelt, OK, ist vermutlich das sauberste, aber im nachhinein gibt es so viele Probleme!
Und autoincrement kannst Du afaik auch gleich vergessen. Das ist zu unflexibel für diese Art von Anwendungen.
Ja, den müsste man selber implementieren. Klar, wenn man den ID Raum aufteilt, kommt man nicht darum herum; es sei denn man könnte den startindex im Tableheader festlegen.
Kann man ja einfach durch einen Dummy-Datensatz mit der ersten ID!
Nun, bei der Synchronisation treten ja leider noch mehr Probleme auf: Was, wenn der Datenbestand auf einer DB ändert, noch während der Synchronisation? - In den meisten Fällen kann man das mit den Flags und Timestamps ja "unterbinden", aber 100% ist die Lösung auch nicht. Man müsste theoretisch während der Synchronisation die Table locken,
genau das habe ich vor!
Ich weiß es einfach nicht. Für die nachträgliche Implementierung sehe ich eigentlich nur eine Chance für 2 Varianten:
1. begrenzter ID-Raum
2. Vergabe und ggfs. Überschreibung der ID durch den Master, und das Feld HerkunftsID, wo immer die ID des Systems der letzten Änderung gespeichert wird. Wenn der Master dann einen Datensatz hat, der nach der letzten Synchronisation geändert wurde, kann man anhand der HerkunftsID sehen ob die Daten auf dem Client aktualisiert werdn müssen. Leider kann man so doch nicht wie ich zunächst annahm Rückschlüsse darauf ziehen ob ein Update oder in Insert von nöten ist. Also muß ich das wohl oder überl doch client-seitig ermittlen. Dann bekomm eich aber Probleme mit den IDs, da sich hier ClientIDs und MasterIDs in einer Spalte mischen. Aber dafür bräuchte ich eine weitere Spalte mit einem Flag welches geändert wird sobald eine Synchronisation erfolgt ist, so kann ich die gültigen MasterIDs herausiltern.
Problem Nr.2 wäre dann noch die Verknüpfungen wieder hinzubiegen. Wie würde man das am besten machen? Das Problem ist, dass das so nicht mehr unabhängig von der Datenstruktur gesehen werden kann, also muß ich das ganz speziell programmieren und bei Änderungen anpassen.
Dann muß ich die alte ID wieder mit zurückschicken und bei jedem Insert die entsprechende Verknüpfung anpassen... sehr kompliziert, vor allem wenn man viele Tabellen hat und viele Verknüpfungen.
Eine andere Lösung wäre es vielleicht, noch ein Feld einzufügen, nämlich eine autoinc-ID des Clients. Aber ich glaube auch das bringt mich nicht wirklich weit nach vorne, denn sobald ich Verknüpfungen habe bekomme ich dasselbe Problem, entweder ich ändere die komplette Struktur der Verknüpfungen auf 2 IDs oder ich versuche es doch mit dem ID-Raum, das wäre das mit Abstand einfachste!
Viele Grüße
Andreas
Hallo!
Habe eine neue Idee, was haltet Ihr von einer "Kombi-Lösung"?
Ich stelle mir das wie folgt vor:
Eine ClintID die jeder Client im Feld ID mit autoincrement vergibt, dann ein Feld HerkunftsID, wo jeweils die ID des Standortes bei jedem Insert gespeichert wird, und als drittes eine Kombination aus beidem, dann verzicht ich halt auf die paar Millisekunden Zeitvorteil wenn ich Integer abfrage, die Zeit geht normalerweise eh woanders verloren, aber wenn ich eine Varchar ID habe, also z.b.
3.12345
^ ^^^^^
| |
| +----- DatensatzID(Client)
+---- HerkunftsID
Welches Format(schreibweise und Spaltenformat) würdet Ihr für eine derarige ID empfehlen?
Diese ID hätte jedenfalls 3 Vorteile
1. ich begrenze nicht den ID-Raum
2. ich behalte eine einzige Eindeutige ID
3. ich kann das System beim nächten größeren Update rel. problemlos auf 2-IDs umstellen
Viele Grüße
Andreas
Halihallo Andreas
Habe eine neue Idee, was haltet Ihr von einer "Kombi-Lösung"?
Meistens gut :-)
Eine ClintID die jeder Client im Feld ID mit autoincrement vergibt, dann ein Feld HerkunftsID, wo jeweils die ID des Standortes bei jedem Insert gespeichert wird, und als drittes eine Kombination aus beidem, dann verzicht ich halt auf die paar Millisekunden Zeitvorteil wenn ich Integer abfrage, die Zeit geht normalerweise eh woanders verloren, aber wenn ich eine Varchar ID habe, also z.b.
3.12345
^ ^^^^^
| |
| +----- DatensatzID(Client)
+---- HerkunftsID
Welches Format(schreibweise und Spaltenformat) würdet Ihr für eine derarige ID empfehlen?
Keine Fliesskommazahl! - Das könnte bei grossen ID's ins Verderben führen, es sei denn, dass die Genauigkeit so hoch ist, dass er auch die 20'ste Stelle noch richtig "abbildet" und nicht rundet. Naja, ich würde eigentlich ein Char nehmen (Index bei Varchar ist lange nicht so effizient); beim Char die Länge 20 oder so. So ist auch der Index noch sehr effizient (anders eben bei Varchar, da hier nur eine "Referenz" verwendet wird und die eigentlichen Daten nicht im Record sind).
- ich begrenze nicht den ID-Raum
- ich behalte eine einzige Eindeutige ID
- ich kann das System beim nächten größeren Update rel. problemlos auf 2-IDs umstellen
Ich glaube, dass dies hinhauen könnte. Bei den Selects verwendest du dann die DatensatzID, oder? - HerkunftsID ist eine eigene Spalte mit Default-Wert und die Synchronisation bringt das dann in eine ID "CHAR-ID". Habe ich das so verstanden?
Viele Grüsse
Philipp
Hi!
Eine ClintID die jeder Client im Feld ID mit autoincrement vergibt, dann ein Feld HerkunftsID, wo jeweils die ID des Standortes bei jedem Insert gespeichert wird, und als drittes eine Kombination aus beidem, dann verzicht ich halt auf die paar Millisekunden Zeitvorteil wenn ich Integer abfrage, die Zeit geht normalerweise eh woanders verloren, aber wenn ich eine Varchar ID habe, also z.b.
3.12345
^ ^^^^^
| |
| +----- DatensatzID(Client)
+---- HerkunftsID
Welches Format(schreibweise und Spaltenformat) würdet Ihr für eine derarige ID empfehlen?
Keine Fliesskommazahl! - Das könnte bei grossen ID's ins Verderben führen, es sei denn, dass die Genauigkeit so hoch ist, dass er auch die 20'ste Stelle noch richtig "abbildet" und nicht rundet. Naja, ich würde eigentlich ein Char nehmen (Index bei Varchar ist lange nicht so effizient); beim Char die Länge 20 oder so. So ist auch der Index noch sehr effizient (anders eben bei Varchar, da hier nur eine "Referenz" verwendet wird und die eigentlichen Daten nicht im Record sind).
Also kein "." als Trennzeichen. Vielleicht ein "-" oder ein "/"? Aber meinst Du das ist so ein Problem? Wenn ich schreibe "WHERE ID = '3.1234123422' sollte das doch als String verstanden werden, zumal es sich ja um keine "Zahlenspalte" handelt! Hast Recht mit Char, das werde ich dann nehmen.
- ich begrenze nicht den ID-Raum
- ich behalte eine einzige Eindeutige ID
- ich kann das System beim nächten größeren Update rel. problemlos auf 2-IDs umstellen
Ich glaube, dass dies hinhauen könnte. Bei den Selects verwendest du dann die DatensatzID, oder? - HerkunftsID ist eine eigene Spalte mit Default-Wert und die Synchronisation bringt das dann in eine ID "CHAR-ID". Habe ich das so verstanden?
Also wie folgt, eine Tabelle hat 5 Spalten:
ID,ClientID,HerkunftsID,timestamp,Vorname(Spalte mit Daten)
ClientID ist mit autoincrement "ausgestattet",
HerkunftsID steht standardmäßig z.B. auf 3, für Standort 3
Jetzt füge ich so Daten ein:
"INSERT INTO tabelle SET ID=HerkunftsID"-"LAST_INSERT_ID(), Vorname = 'Hugo'"
vermutlich geht da so nicht ;-) aber so in der Art wäre es mir am liebsten. LAST_INSERT_ID() sollte die neu erzeugte ClientID sein, und HerkunftsID soll den Standardwert aus selbiger Spalte zurückgeben.
Dann habe ich zwar die Information doppelt in jeder Tabelle stehen, aber dafür die zusammengesetze ID in einer Spalte. So vermeide ich das ich immer 2 Spalten zur eindeutigen Indentifikation benötige, und ich umgehe das Problem mit der nachträglichen Aktualisierung der verknüpften Datensätze.
Grüße
Andreas
Viele Grüsse
Philipp
Halihallo Andreas
Welches Format(schreibweise und Spaltenformat) würdet Ihr für eine derarige ID empfehlen?
Keine Fliesskommazahl! - Das könnte bei grossen ID's ins Verderben führen, es sei denn, dass die Genauigkeit so hoch ist, dass er auch die 20'ste Stelle noch richtig "abbildet" und nicht rundet. Naja, ich würde eigentlich ein Char nehmen (Index bei Varchar ist lange nicht so effizient); beim Char die Länge 20 oder so. So ist auch der Index noch sehr effizient (anders eben bei Varchar, da hier nur eine "Referenz" verwendet wird und die eigentlichen Daten nicht im Record sind).
Also kein "." als Trennzeichen. Vielleicht ein "-" oder ein "/"?
Du kannst auch gerne ein "." als Trennzeichen nehmen, womit du trennst spielt keine Rolle, nur, wenn du auf die, wie gesagt sehr waghalsige, Idee kommst, den Spaltentyp auf Float zu setzen.
Aber meinst Du das ist so ein Problem? Wenn ich schreibe "WHERE ID = '3.1234123422' sollte das doch als String verstanden werden, zumal es sich ja um keine "Zahlenspalte" handelt! Hast Recht mit Char, das werde ich dann nehmen.
Dies wird als Zahl behandelt, wenn der Spaltentyp einen Zahlentyp ist und wird als String behandelt, wenn es ein Stringtyp (CHAR) ist. Also, du wirst keine Probleme haben, wenn du den Spaltentyp auf einen geeigneten CHAR setzt (dir ist aber klar, dass du hier mit 4 Bytes nur 10000 Records ansprechen kannst; anders als INT - Werte).
- ich begrenze nicht den ID-Raum
- ich behalte eine einzige Eindeutige ID
- ich kann das System beim nächten größeren Update rel. problemlos auf 2-IDs umstellen
Ich glaube, dass dies hinhauen könnte. Bei den Selects verwendest du dann die DatensatzID, oder? - HerkunftsID ist eine eigene Spalte mit Default-Wert und die Synchronisation bringt das dann in eine ID "CHAR-ID". Habe ich das so verstanden?
Also wie folgt, eine Tabelle hat 5 Spalten:
ID,ClientID,HerkunftsID,timestamp,Vorname(Spalte mit Daten)
ClientID ist mit autoincrement "ausgestattet",
HerkunftsID steht standardmäßig z.B. auf 3, für Standort 3
Jetzt füge ich so Daten ein:
"INSERT INTO tabelle SET ID=HerkunftsID"-"LAST_INSERT_ID(), Vorname = 'Hugo'"
vermutlich geht da so nicht ;-) aber so in der Art wäre es mir am liebsten. LAST_INSERT_ID() sollte die neu erzeugte ClientID sein, und HerkunftsID soll den Standardwert aus selbiger Spalte zurückgeben.
Dann habe ich zwar die Information doppelt in jeder Tabelle stehen, aber dafür die zusammengesetze ID in einer Spalte. So vermeide ich das ich immer 2 Spalten zur eindeutigen Indentifikation benötige, und ich umgehe das Problem mit der nachträglichen Aktualisierung der verknüpften Datensätze.
OK. Verstehe. Dein pseudo-INSERT kannst du übrigens dennoch vollständig durch die DB erstellen:
nach jedem Insert...
UPDATE table SET ID=CONCAT(HerkunftsID, '-', ClientID) WHERE ID=0
so musst du das nicht "programmiertechnisch" lösen... Und wenn du über ID noch einen Index legst, ist diese Lösung sogar ziemlich performant. Das nur so als Tip nebenbei ;)
Viele Grüsse
Philipp
Hallo Philipp!
Du kannst auch gerne ein "." als Trennzeichen nehmen, womit du trennst spielt keine Rolle, nur, wenn du auf die, wie gesagt sehr waghalsige, Idee kommst, den Spaltentyp auf Float zu setzen.
Ich will ja gar nicht mehr trennen, das soll nur _eine_ eindeutige ID sein!
Dies wird als Zahl behandelt, wenn der Spaltentyp einen Zahlentyp ist und wird als String behandelt, wenn es ein Stringtyp (CHAR) ist. Also, du wirst keine Probleme haben, wenn du den Spaltentyp auf einen geeigneten CHAR setzt (dir ist aber klar, dass du hier mit 4 Bytes nur 10000 Records ansprechen kannst; anders als INT - Werte).
??? Verstehe ich nicht. Wie meinst Du das?
OK. Verstehe. Dein pseudo-INSERT kannst du übrigens dennoch vollständig durch die DB erstellen:
nach jedem Insert...
UPDATE table SET ID=CONCAT(HerkunftsID, '-', ClientID) WHERE ID=0
Aber geht denn nichz sowas wie
INSERT INTO table SET ID=CONCAT(HerkunftsID, '-', ClientID)???
Das mir am liebsten! Aber da ich das eh in e ine Funktion packe soll mir das auch recht sein, nur sollte Deine VErsion wohl besser so aussehen:
INSERT INTO table SET Vorname='Franz-Joseph';
UPDATE table SET ID=CONCAT(HerkunftsID, '-', ClientID) WHERE ID=LAST_INSERT_ID();
oder?
so musst du das nicht "programmiertechnisch" lösen... Und wenn du über ID noch einen Index legst, ist diese Lösung sogar ziemlich performant. Das nur so als Tip nebenbei ;)
KLar, ein Index muß sein, ich denke so mach eihc es auch, dann reicht es die Inserts auf eine Funktion umzustellen und der Rest bleibt!
Danke Dir!
Viele Grüße
Andreas
Halihallo Andreas
Dies wird als Zahl behandelt, wenn der Spaltentyp einen Zahlentyp ist und wird als String behandelt, wenn es ein Stringtyp (CHAR) ist. Also, du wirst keine Probleme haben, wenn du den Spaltentyp auf einen geeigneten CHAR setzt (dir ist aber klar, dass du hier mit 4 Bytes nur 10000 Records ansprechen kannst; anders als INT - Werte).
??? Verstehe ich nicht. Wie meinst Du das?
CHAR ist ja ein String. Also, wenn du vier Bytes für den CHAR reservierst, kannst du nur die Zahlen '0000' bis '9999' speichern; '10000' bräuchte ja schon 5 Bytes. Anders bei Integern, da kannst du auf 4 Bytes natürlich 2^32 Zahlen "schreiben". Beim speichern von Zahlen in Strings benutzt du ja nur 10 von 256 möglichen Zeichen.
OK. Verstehe. Dein pseudo-INSERT kannst du übrigens dennoch vollständig durch die DB erstellen:
nach jedem Insert...
UPDATE table SET ID=CONCAT(HerkunftsID, '-', ClientID) WHERE ID=0
Aber geht denn nichz sowas wie
INSERT INTO table SET ID=CONCAT(HerkunftsID, '-', ClientID)???
Nein, da zum Zeitpunkt des Insert's noch gar keine HerkunftsID und ClientID definiert ist, die werden ja erst _während_ dem Insert "bekannt".
Das mir am liebsten! Aber da ich das eh in e ine Funktion packe soll mir das auch recht sein, nur sollte Deine VErsion wohl besser so aussehen:
INSERT INTO table SET Vorname='Franz-Joseph';
UPDATE table SET ID=CONCAT(HerkunftsID, '-', ClientID) WHERE ID=LAST_INSERT_ID();
oder?
Ich glaube, dass dies keine Probleme geben sollte. Probleme gäbe es, wenn LAST_INSERT_ID nicht Sessionabhängig wäre; müsstest du in der Doku nachschlagen. Das Problem wäre:
Wenn zwischen dem INSERT und UPDATE noch ein INSERT aus einem anderen Prozess stattfinden würde, und last-insert-id nicht sessionabhängigwäre, würdest du die neue ID des insert's des anderen Threads ändern und gar nicht den, den du ändern möchtest. Wenn jedoch die last_insert_id Sessionabhängig wäre (was ich glaube), dann hast du keine Probleme, da sich der update in jedem Fall auf den vorherigen insert bezieht. Mit ID=0 bist du auf jeden Fall auf dem sicheren Pfad und mit Index sogar noch einigermassen Performant. Wenn es jedoch keinen grossen Arbeitsaufwand bedeutet würde ich deine Version natülich auch bevorzugen.
Viele Grüsse
Philipp
Hallo!
CHAR ist ja ein String. Also, wenn du vier Bytes für den CHAR reservierst, kannst du nur die Zahlen '0000' bis '9999' speichern; '10000' bräuchte ja schon 5 Bytes. Anders bei Integern, da kannst du auf 4 Bytes natürlich 2^32 Zahlen "schreiben". Beim speichern von Zahlen in Strings benutzt du ja nur 10 von 256 möglichen Zeichen.
Ja, aber das schlägt sich ja nur zum einen im Speicherverbrauch und der Begrenzung der IDs nieder, oder? Ich bezweifele aber das ich da irgendwo an Grenzen stoße!
Das mir am liebsten! Aber da ich das eh in e ine Funktion packe soll mir das auch recht sein, nur sollte Deine VErsion wohl besser so aussehen:
INSERT INTO table SET Vorname='Franz-Joseph';
UPDATE table SET ID=CONCAT(HerkunftsID, '-', ClientID) WHERE ID=LAST_INSERT_ID();
oder?
Ich glaube, dass dies keine Probleme geben sollte. Probleme gäbe es, wenn LAST_INSERT_ID nicht Sessionabhängig wäre; müsstest du in der Doku nachschlagen. Das Problem wäre:
Soweit ich weiß bleibt die eine Verbindung ja über die Laufzeit des Scriptes bestehen, und auf diese Verbindung bezieht sich LAST_INSERT_ID meines Wissens! Sonst wäre die Funktion totaler Schwachsinn ;-)
Grüße
Andreas
Halihallo Andreas
CHAR ist ja ein String. Also, wenn du vier Bytes für den CHAR reservierst, kannst du nur die Zahlen '0000' bis '9999' speichern; '10000' bräuchte ja schon 5 Bytes. Anders bei Integern, da kannst du auf 4 Bytes natürlich 2^32 Zahlen "schreiben". Beim speichern von Zahlen in Strings benutzt du ja nur 10 von 256 möglichen Zeichen.
Ja, aber das schlägt sich ja nur zum einen im Speicherverbrauch und der Begrenzung der IDs nieder, oder? Ich bezweifele aber das ich da irgendwo an Grenzen stoße!
Genau. Wollte ich auch nicht anzweifeln, sondern nur zu bedenken geben ;-)
CHAR könnten bis 255 Bytes lange werden => das gibt dann einen Zahlenbereich von 0 - (10^255 - 1)... Ja, ich glaube auch, dass das für deine Zwecke ausreicht und sonst kannst du ja auf TEXT umsteigen, dort hast du dann 2^24 Bytes zur Verfügung :-)
Ich glaube, dass dies keine Probleme geben sollte. Probleme gäbe es, wenn LAST_INSERT_ID nicht Sessionabhängig wäre; müsstest du in der Doku nachschlagen. Das Problem wäre:
Soweit ich weiß bleibt die eine Verbindung ja über die Laufzeit des Scriptes bestehen, und auf diese Verbindung bezieht sich LAST_INSERT_ID meines Wissens! Sonst wäre die Funktion totaler Schwachsinn ;-)
Das meinte ich und ich hatte die gleichen Überlegungen gemacht. Also: Du hast grünes Licht :-)
Viele Grüsse
Philipp
Halihallo Andreas
-- hier komme ich nicht weiter. --
Das Problem besteht darin, die auf dem Client nicht vorhandenen Datensätze herauszufinden. OK, man kann auch hier den Zeitpunkt der letzten Synchronisation ermitteln (da komme ich wohl nicht drum herum wegen der Updates), aber wie unterscheide ich zwischen Insert und Update? Woher weiß ich ob der Datensatz jetzt neu angelegt wurde und noch nicht auf dem Client vorhanden ist, oder ob er lediglich geändert wurde? Ich kann ja leider nicht mit einem Insert einen vorhandenen Datensatz mit gleicher ID überschreiben!
Naja, dann kannst du ja einen DELETE FROM WHERE ID=xxx vorn anhängen, der einen potenziellen Eintrag löscht und ihn durch den neuen ersetzt, oder?
Hat jemand ne Idee wie ich das Problem lösen kann? Ich möchte hierbei nicht in die eigentliche Anwendung(d.h. die Anwendung die synchronisiert werden soll) eingreifen, d.h. deren INSERT-Statements verändern. Gibt es eine Möglichkeit in MySQL einen automatischen Timestamp für die Erstellung des Datensatzes einzufügen? Sowas der Art den Standardwert vom 2. Timestamp auf NOW() setzen(geht leider nicht)?
Naja, ich hab etwas den Überlick verlohren, muss ich gestehen; aber vielleicht habe ich hierzu einen Einwurf, der eventuell etwas tauen könnte: Automatisch glaube ich nicht, dass du ne timestamp in die DB schreiben kannst, aber wenn die Spalte vorhanden ist und du keine Änderungen an den Programmen selber vornehmen möchtest, dann gäbe es noch die Möglichkeit über einen hintergrundsprozess, der z. B. alle 10 Minuten anspringt und neue Records mit der "nahezu" aktuellen Timestamp versieht. So hast du wenigstens eine Näherung; ob die ausreicht und ob der Arbeitsaufwand OK ist, müsstest du entscheiden.
Sonst fiele mit nur ein _noch ein weiteres_ Feld in jede Tabelle einzufügen, und zwar mit einem Synchronisations-Status, standardmäßig auf 0, nach der Synchronisation auf 1 gesetzt.
Dafür behält das HerkunftID Feld für immer seine ID. Jetzt kann ich auf dem Client anhand des Statusfeldes sehen, ob der Datensatz bereits synchronisiert wurde, und auf dem Master kann ich an dem HerkunftsID Feld sehen, ob der Datensatz schon auf dem Client vorhanden ist.
Aber dann hätte ich schon 2 extra Felder, hat vielleicht jemand ne bessere Idee?
Ich würde gerne helfen, aber... (vielleicht fällt mir ja morgen was schlaues ein)
Viele Grüsse
Philipp
<-- der sein Hirn vielleicht noch nicht ganz eingeschaltet hat...
Moin,
Automatisch glaube ich nicht, dass du ne timestamp in die DB schreiben kannst, aber wenn die Spalte vorhanden ist und du keine Änderungen an den Programmen selber vornehmen möchtest, dann gäbe es noch die Möglichkeit über einen hintergrundsprozess, der z. B. alle 10 Minuten anspringt und neue Records mit der "nahezu" aktuellen Timestamp versieht.
MySQL ist so freundlich das erste TIMESTAMP-Feld in einer Zeile bei einem UPDATE oder INSERT automagisch auf die aktuelle Zeit zu setzen, wenn dafür bei der entsprechenden Operation nicht explizit ein Wert angegeben oder er auf NULL gesetzt wird und bei der Operation ein anderes Feld seinen Wert verändert. Das nur als Gegeneinwurf.
--
Henryk Plötz
Grüße von der Ostsee
Hallo Andreas,
schau Dir doch mal die Sozialversicherungsnummer oder die Dienstnummer bei der Bundeswehr an.
Beides sind zusammengesetzte Schlüssel, die eindeutig die verschiedenen Dimensionen der Datenspeicherung (Vergabestelle, Geburtsdatum, Anfangsbuchstabe des Geburtsnachnamens, lfd.Nummer) berücksichtigen.
Diese Schlüssel haben sich seit mehr als 50 Jahren bewährt - ich will fast behaupten seit Jaquard (1805) oder Hollerit (1886).
Wenn Du das was Neues erfindest, gebührt Dir ein Nobelpreis. Allerdings glaube ich nicht daran, dass Du das schaffst.
Gruß
Tom
Hi!
schau Dir doch mal die Sozialversicherungsnummer oder die Dienstnummer bei der Bundeswehr an.
Beides sind zusammengesetzte Schlüssel, die eindeutig die verschiedenen Dimensionen der Datenspeicherung (Vergabestelle, Geburtsdatum, Anfangsbuchstabe des Geburtsnachnamens, lfd.Nummer) berücksichtigen.
Diese Schlüssel haben sich seit mehr als 50 Jahren bewährt - ich will fast behaupten seit Jaquard (1805) oder Hollerit (1886).
Da gabs aber auch noch keine Computer, an die man denken könnte!
Im Prinzip ist eien Zweiteilige ID auch möglich, nur dachte ich mir es sei sehr viel besser immer über INT-Werte abzufragen!
Grüße
Andreas
Hi Andreas,
na klar geht das auch über Int-Werte.
Kenn ich auch ein Beispiel dafür: 212.83.63.162
Ist in Wirklichkeit ein 32Bit-unsigned-Integer.
Musst Du eben Nummernkreise einführen. Damit teilst Du dann, genauso wie bei der IP, soundsoviele Bits der Klasseneinteilung zu und die anderen der laufenden Nummer. Du hast eben zwei Dimensionen und die multiplizieren sich.
Grüße
Tom
Hallo!
na klar geht das auch über Int-Werte.
Kenn ich auch ein Beispiel dafür: 212.83.63.162
Ist in Wirklichkeit ein 32Bit-unsigned-Integer.
Willst Du mir jetzt erzählen das 212.83.63.162 ein Interger ist? Das sind 4 Integer getrennt durch 3 Punkte, welches Format wäre das denn für MySQL? Aber das ist auch egal, das Problem ist eine schnelle und automatische Vergabe der nächsten gültigen ID, und daber darf nichts übersprungen werden, sonst ist man schneller am Ende der Fahnenstange als man glaubt!
Musst Du eben Nummernkreise einführen. Damit teilst Du dann, genauso wie bei der IP, soundsoviele Bits der Klasseneinteilung zu und die anderen der laufenden Nummer. Du hast eben zwei Dimensionen und die multiplizieren sich.
2-10 Dimensionen, und was wenn ich dann doch unerwarteterweise an eine Grenze stoße?
Viel Grüße
Andreas
Hallo,
na klar geht das auch über Int-Werte.
Kenn ich auch ein Beispiel dafür: 212.83.63.162
Ist in Wirklichkeit ein 32Bit-unsigned-Integer.
Willst Du mir jetzt erzählen das 212.83.63.162 ein Interger ist? Das sind 4 Integer getrennt durch 3 Punkte, welches Format wäre das denn für MySQL?
Naja, es sind 4 Bytes, deren Werte in dezimaler Schreibweise angegeben werden, und 4 Bytes sind nun mal ein 'long Integer';-)
Grüße
Klaus
Hallo!
Naja, es sind 4 Bytes, deren Werte in dezimaler Schreibweise angegeben werden, und 4 Bytes sind nun mal ein 'long Integer';-)
Wenn DU mir jetzt noch verrätst wie man genau so eine "Zahl" in MySQl schreibt, d.h. welches Format die spalte haben muss, dann wäre ich glücklich! Wenn ich mich nicht irre sind das 4 Byte also 32 Bit also 2^32 zahlen also kann man Zahlen von 1-4294967296 verwenden, oder war das von -2147483648 bis +2147483648? Jedenfalls kann man slche Zahlen prima in ein long Integer Feld schreiben. Wie würde das denn in der Praxis aussehen? Was schreibe ich letztendlich für Zahlen in welches Feldformat?
Grüße
Andreas