Moin!
schon hast du 9 Standorte. Wenn dann noch ein Backup-System für den Shop dazukommt (zweiter Server, kriegt bis zum Ernstfalleinsatz immer nur Daten geliefert - Nummer 10) ein Server der nur loggt braucht keien ID, denn da kanes zu keinen Konflikten kommen!
Naja, wenn der Server später mal Daten erfassen soll (und sowas sollte man nicht ausschließen), dann braucht er doch eine ID - warum vorher knausern? Eben...
Ja, aber mir ist aufgefallen das das Problem ja überhaupt gar nicht besteht. Die einzige Beschränkung besteht in der begrenzten Anzahl an Datensätzen! Denn ich verwende das ja immer wie folgt, um die höchte ID des Standortes 5 zu ermitteln:
SELECT ID FROM tabelle WHERE ID >=50000000 AND ID < 600000000 ORDER bY ID DESC
Naja, wenn plötzlich in einer Datenbank mehr Datensätze anfallen, als du eingeplant hast, dann hast du ein Problem. Dann musst du deine Datenbankabfragen alle modifizieren, UND du musst alle deine IDs modifizieren.
Auch wenn in der Realität dieses Problem noch nicht zu erwarten ist: Es ist theoretisch möglich. Du begrenzt die normalerweise ganz simpel hochzählbare ID künstlich, indem du der ersten Stelle eine besondere Bedeutung gibst. Dasselbe Problem (künstliche Begrenzung nach oben, weil "da noch viel Platz ist" gabs in der Computergeschichte schonmal: Beim PC wurde das Speicher-Layout im ersten Megabyte so angeordnet, dass von 0 bis 640 KB RAM vorlag, darüber Speicherplatz für Steckkarten, genutzt als erweiterter DOS-Speicher, und ganz am Ende an der Grenze zu 1MB kam ROM-BIOS. Das Problem: Speichererweiterungen müssen "dahinter" ansetzen, und schon war eine sehr unschöne Barriere im Speicherbild.
Mit anderen Worten: "Sowas macht man nicht"[tm]. :)
Was spricht dagegen, lieber SELECT id, db_id FROM tabelle WHERE db_id = 5 ORDER BY id DESC zu verwenden. Da kannst du die db_id ebenfalls beliebig hochzählen, hast keinerlei Probleme mit Erweiterungen.
Wenn du unbedingt deine "alles-in-einer"-ID beibehalten willst und wirklich nur zehn Datenbanken betreiben willst, dann packe die Datenbank-ID in die letzte ID-Stelle. Da stört sie die Erweiterung nach oben nicht - ist allerdings auch schwerer abzufragen - und vermutlich mit wesentlich mehr Performance-Einsatz. Im Prinzip wäre es notwendig, durch eine Berechnung (Modulo-Operation) die ID erstmal "vorzubehandeln", bevor mit der gewünschten Datenbank-ID verglichen werden kann. Dann doch lieber zwei Spalten.
Und nochwas, die Int-Felder in MySQL sind an sich auf 2147483647 begrenzt, das ist gar nicht so viel mehr als ich jedem Standort zur Verfügung stelle!
Primary IDs sind bei mir grundsätzlich BIGINT. Für eine ID, deren einzige Aufgabe es ist, mit jedem neuen Datensatz hochgezählt zu werden, scheint mir das kein Probleme zu bergen. Und 18446744073709551616 Datensätze sind so schnell nicht angelegt. Und wenn das nicht reicht, läßt sich die ID vom System her beliebig nach oben erweitern (sofern man eine entsprechende Datenbank und passende Hardware hat - 128-Bit-Systeme lassen grüßen).
Es geht mir hier aber weniger um die Geschwindigkeit, mehr um den Aufwand der Implementierung. Wenn irgend möglich sollte das auch für bestehende Projekte anwendbar sein. Und da finde ich es erheblich einfacher die paar INSERTs über eine neu Funktion zu schreiben, als alle SELECTs, alle Links.... und was alles daran hängt neu zu schreiben, der Aufwand dürfte 20-50 mal so groß sein!
Wenn du keine separate Spalte für die Datenbank-ID verwenden willst, dann kannst du diese Information auch im Tabellennamen verpacken. Das ist allerdings keine gut handhabbare Idee, weil du dann nicht mit einer Tabelle arbeitest, sondern mindestens mit zwei Tabellen (einer mit zentral schon gespeicherten Daten, und einer mit neuen lokalen Daten).
Ich bin sicher, du bist dir dessen bewußt, trotzdem sag' ich es nochmal: Verteilte Datenbanksynchronisation ist keineswegs trivial. Erwarte nicht, dass ein System, welches total auf zentrale Datenhaltung ausgerichtet ist, sich ohne irgendeinen Aufwand "mal eben" auf Mehrstandortbetrieb umstellen läßt. Knackpunkt ist, dass du unter Berücksichtigung allgemeiner Datenbankerstellungsregeln die Synchronisation hinkriegst.
Ich möchte nach Möglichkeit vermeiden das man das komplett für die Synchronisierung programmieren muß. Ich suche eher die Möglichkeit eine X-belibige Tabelle synchronisieren zu können, indem ich einfach die Methode zum schreiben von Datensätzen verändere, am besten über ein Klasse global. Wenn ich mich dann halt auf 10 Mio Datensätze beschränken muß - Pech, das Leben ist hart, aber wie gesagt, das ist extrem unwahrscheinlich. Ich weiß, das sollte man nicht machen, aber sei doch mal realistisch - ist das wirklich der Aufwand wert?
Sorry, aber ich halte es für einen Irrglauben, dass es so einfach ist. Du musst nicht nur die Funktionen zum Datenschreiben anpassen, sondern natürlich auch an den Funktionen zum Datenlesen rumschrauben.
Außerdem: Wie lange soll dein System laufen? Nein, falsch gefragt. Wie lange soll deine Datenbank mit den Daten laufen? Das System drumherum kann sich ja ändern, aber die Daten leben meist wesentlich länger. Wenn du 10 Millionen Datensätze erlaubst, dann kann deine Datenbank "nur" 20 Jahre lang laufen, sofern 8 Stunden am Tag, 365 Tage im Jahr jede Minute 2 Datensätze eingegeben werden. Gut, 20 Jahre sind eine lange Zeit, und die Zahl der Datensätze erscheint relativ hoch, aber die Lebensdauer ist grundsätzlich begrenzt. Sowas einzubauen ist schlecht. Stell dir vor, der Internetshop nimmt plötzlich große Ausmaße an, und kriegt statt 2 Bestellungen jede Minute 20 Bestellungen je Minute. Dann reicht die Datenbank nur noch 2 Jahre aus - und das ist durchaus unangenehm!
Ich war insgesamt auf folgende Modelle gekommen
- wie beschreiben, eine ID die sich aus Standort_ID und Datensatz-ID zusammensetzt
Und als schlecht verworfen wurde.
- Master-Server der IDs verteilt, Client-Server haben sowohl eigene IDs, und die des Master
Das wäre noch eine Idee. Der Master-Server liefert ID-Bereiche, die von den einzelnen Sub-Datenbanken verwendet werden können, und sorgt damit für eine gleichmäßige Ausnutzung des ID-Bereichs. Man kann Hunderter- oder Tausenderblöcke verteilen, und wenn ein Block voll ist, wird der nächste abgefordert. Damit kriegst du nur nicht mehr raus, von welcher Datenbank der ursprüngliche Eintrag erfolgte.
- Direkte Anbindung an Master-Server, direkt IDs holen
Hattest du schon als undurchführbar beschrieben.
- Nur Master-DB, rest nur Spiegelungen zur Sicherheit
Ist genauso schlecht, weil's dauerhafte Verbindungen erfordert.
Das doofe daran, ich habe eine andere Tabelle auf dem Master als auf dem Client, und das an sich ist schonmal großer Mist! Das verkompliziert einige Dinge ganz schön!
Du hast ja auch unterschiedliche Aufgaben für den Master und den Client - da sind unterschiedliche Tabellen durchaus erlaubt. Du kannst die Tabellen aber vollkommen identisch gestalten und nur je nach Aufgabe (Master, Client) unterschiedliche Abfragen machen. Das ID-Feld, für das du keinen Wert hast, bleibt eben NULL (auch wenn NULL nicht unbedingt ein schöner Zustand ist).
2.) 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. Die Idee gefällt mir wiederum SEHR gut! Vor allem könnte ich in jeder DB das Herkunfsfeld standardmäßig auf die StandortID stellen, also merke ich das nichtmal! Fast perfekt! Der einzige Wehrmutstropfen: Angenommen ich habe wirklich Probleme mit meiner Internetvernbindung, ein Kunde bestellt, ich gebe das manuell ein, und will direkt eine Rechnung drucken - was verwende ich dann für eine Rechnungsnummer? Die ID die es einige Stunden später nicht mehr gibt? Eine eindeutige Rechnungsnummer hat wieder dasselbe Problem. Das Problem besteht bei meiner favorisierten Variante wiederum nicht - die ID ist sofort eindeutig!
Eine Rechnungsnummer hat nicht zwingend irgendwas mit der Datensatz-ID zu tun. Ok, irgendeine Identifikation muss man haben. Wenn du auf eine andere Weise feststellen kannst (Timestamp), welche Datensätze schon abgeglichen sind, dann kannst du auf das Umschreiben der Datensatz-ID verzichten - die Kombination aus ID und Herkunftsfeld ist eindeutig zum Auffinden des Datensatzes.
Wenn du Rechnungsnummern generieren und zuordnen musst - nimm doch den Timestamp zusammen mit dem Herkunftsfeld. Oder du sorgst doch dafür, dass der Master-Server eigene IDs vergibt und diese eindeutig durchnumeriert - die schon vorhandenen IDs aber nicht überschreibt. Das hängt IMO ein wenig vom Feintuning und den anfallenden Aufgaben ab.
- den ID Raum vorher zwischen den Standorten aufteilen
- ein 2. Feld mit der Standort-ID zur eindeutigen Identifizierung
Die Zweite ist ohne Zweifel sauberer, und die letzte von Dir vorgeschlagene Variante schmeckt mir wirklich gut, aber die erste Variante umgeht sehr viele andere Probleme bei der Programmierung der eigentlichen Anwendung. Bleibt die Frage ob die Beschränkung des ID-Raums wirklich problematisch ist, oder ob es nur unschön programmiert ist, halt ob die Vorteile die Nachteile aufwiegen.
Es widerstrebt mir extremst, in eine Datenbank irgendwelche künstlichen Beschränkungen einzubauen, die irgendwann einmal (wie lange deine 10 Millionen Datensätze reichen, hab ich oben vorgerechnet) systemimmanent zum GAU führen. Wenn du definierst: "Primärschlüssel ist eine natürliche Zahl, welche immer um 1 erhöht wird", dann hängt die konkrete Umsetzung in eine Datenbank nur davon ab, wieviele Bit das DBMS für Zahldarstellungen anbietet. Du kannst kleine Datenbanken mit 16 Bit-ID-Länge schreiben (65536 Datensätze reichen schon eine Weile), oder die ID auf 32, 64, 128, 256 Bit aufbohren, ganz wie die Erfordernisse sind. Du bist nur durch die praktischen Möglichkeiten des konkreten DBMS begrenzt, aber nicht durch dein Konzept der Datenbank. Das ist gut[tm].
Man MUSS irgendwo beschränken, ich könnte ja dafür auch eine BIGINT mit 12 oder noch mehr Stellen nehmen. Meinst Du das ist wirklich so schlimm? Oder solte man die Bereiche lieber über Bit-Bereiche beschränken? Was meinst Du?
Auf alle Fälle Danke für Deine Antwort, Deine Idee ist wirklich gut und vielleicht kommt sie sogar zum Einsatz, aber ich weiß es einfach nicht. Ich will auch nicht einfach anfangen um dann später alles umzuschmeißen ;-)
Eben: Vom Konzept hängt alles ab. Ich hab gewisse Kontakte zu einer Vereinsverwaltungssoftware (Access-Anwendung), bei der die Synchronisation grausamst gelöst wurde. Da werden jeweils komplette Datenbanktabellen hin- und herkopiert - entsprechend aufwendig ist es, wenn mehrere Vereinsmitglieder an mehreren Standorten Änderungen an "ihren" Tabellen vorgenommen habe, diese zusammenzutragen und wieder an die Standorte/Mitglieder zu verteilen. Dabei ist es bei einer Vereinsverwaltungssoftware eigentlich logisch, dass Daten nicht ständig online bearbeitet werden können. Konzept schlecht - Anwendung schlecht - Usability schlecht - Möglichkeiten schlecht.
Planung ist alles. Deshalb macht es Sinn, auf alle Eventualitäten vorbereitet zu sein. :)
- Sven Rautenberg