Andreas: 2-Teileige ID

Hallo!

Ich brauche einen Primärschlüssel über 2 Felder. Aber da ich das auch in bestehende Anwendungen integrieren will, und sämtliche SELECT Abfragen über das eine Feld ID abfragen, würde ich gerne die beiden IDs in einer ID zusammenfassen, aber derart das ich sie auch wieder tennen kann.
die Erste ID könnte ruhig eine Zahl zwischen 1-9 sein, dei steht für den Standort, die ander ID ist die autoincrement ID des Datensatzes. Die IDs sollten aber überall gleich sein.
Ich dachte erst an ein Trennzeichen, oder Buchstaben, aber dadurch wird SELECT wohl deutlich langsamer, als bei Integer, oder?

Also habe ich mir überlegt, ich verwene eine 8-Stellige INT, und zwar die 1. Zahl für den Standort, und die anderen 7 für die ID.

Das hatte ich dann so vor, das ich z.B. an Standort 7 mit 70000001 starte, udn dann per autoincrement hochzähle, bei Standort 3 bei 30000001... so kann ich immer noch unterscheriden was von welchem Standort kommt,und vor allem überschneiden isch die IDs nicht!

Was haltet Ihr davon, würdet Ihr das evtl anders einteilen?

Grüße
Andreas

  1. Hallo!

    Ich brauche einen Primärschlüssel über 2 Felder.

    Ein Primärschlüssel ist ein Primärschlüssel ist ein Primärschlüssel. Er ist für Zuordnungszwecke da, um relationale Strukturen aufbauen zu können, aber er ist nicht dazu da, irgendwelche weiteren Ordnungsmerkmale zu haben.

    Aber da ich das auch in bestehende Anwendungen integrieren will, und sämtliche SELECT Abfragen über das eine Feld ID abfragen, würde ich gerne die beiden IDs in einer ID zusammenfassen, aber derart das ich sie auch wieder tennen kann.

    Erzähle, welche beiden angeblichen IDs du hast, welche Bedeutung sie haben, warum und wie du diese beiden IDs verwenden willst.

    die Erste ID könnte ruhig eine Zahl zwischen 1-9 sein, dei steht für den Standort, die ander ID ist die autoincrement ID des Datensatzes. Die IDs sollten aber überall gleich sein.

    Die Gefahr besteht, dass sich der Standort ändern kann. Oder dass sich plötzlich mehr als 10 Standorte ergeben. In beiden Fällen würdest du die bislang eindeutige ID verändern bzw. an Grenzen gelangen, die vollkommen unnötig sind.

    Ich dachte erst an ein Trennzeichen, oder Buchstaben, aber dadurch wird SELECT wohl deutlich langsamer, als bei Integer, oder?

    Trenne gedanklich die optische Darstellung der ID von der tatsächlichen ID-Speicherung in der Datenbank!

    Was haltet Ihr davon, würdet Ihr das evtl anders einteilen?

    Wenn du sagst, welche Informationen du hast, welche Bedeutung sie haben, und wie sie verknüpft sind, dann kann man einen besseren Vorschlag machen.

    - Sven Rautenberg

    1. Hi Sven!

      die Erste ID könnte ruhig eine Zahl zwischen 1-9 sein, die steht für den Standort, die ander ID ist die autoincrement ID des Datensatzes. Die IDs sollten aber überall gleich sein.

      Die Gefahr besteht, dass sich der Standort ändern kann. Oder dass sich plötzlich mehr als 10 Standorte ergeben. In beiden Fällen würdest du die bislang eindeutige ID verändern bzw. an Grenzen gelangen, die vollkommen unnötig sind.

      Das ist dann mein Problem. Wenn es > 9 Standorte geben sollte mach ich ein Faß auf und besauf mich, zumindest sehe ich zur Zeit (leider) nicht in Ansätzen das die Zahl erreicht wird. Und wenn das so ist kann ich mir ja immer noch Gedanken machen. Ich weiß, das sollte man nicht, aber der Preis den ich jetzt dafür bezahle das ich es mir offen halte das es mal so viele Standorte geben wird, ist dermaßen hoch das er durch die geringe Eintrittswahrscheinlichkeit dieses Falles nicht gerechtfertigt ist - es sei denn Du weißt eine Lösung. Zur Not mache 90 Standorte werden, und das ist nun wirklich unmöglich! Dan muß ich abeer am besten die Stellen direkt auf 10 erhöhen.

      Ich dachte erst an ein Trennzeichen, oder Buchstaben, aber dadurch wird SELECT wohl deutlich langsamer, als bei Integer, oder?

      Trenne gedanklich die optische Darstellung der ID von der tatsächlichen ID-Speicherung in der Datenbank!

      Ja, das hört sich so an als wäre das für die Optik, ist es aber nicht. Es ist für einen Synchronisationsmechanismus, den ich auf jede Tabelle anwenden kann, die einen Timestamp und eine derartige 2-teile ID enthält.

      Was haltet Ihr davon, würdet Ihr das evtl anders einteilen?

      Wenn du sagst, welche Informationen du hast, welche Bedeutung sie haben, und wie sie verknüpft sind, dann kann man einen besseren Vorschlag machen.

      OK, aber das ganze ist kompliziert ;-)

      Ich habe hier immer mal wieder Threads gestartet, von wegen Synchronisation 2er Datenbanken, genauer einiger bestimmter Tabellen die in 2(und mehr) Datenbanken vorkommen, und in denen parallel Aktualisierungen vorgenommen werden(ich weiß, da braucht es Regeln...), die aber nur über das Internet verbunden sind, und das auch nicht über eine Standleitung. Die höchste Priorität hat die lokale Verfügbarkeit der Daten. Ich habe 4 lokal voneinander getrennte Standorte mit eigenen LANs, jeweils mit eigenem Apache/MySQl Server. 1 davon läuft unter Linux(Online-Shop beim Provider), die andern(Verkauf, Verwaltung) unter Win2K.
      In allen Datenbanken sollen möglichst aktuelle Daten stehen, Änderungen, neue Einträge... sollen in allen Datenbanken mit der Synchronisation vorgenommen werden.

      Jetzt habe ich z.B. in allen Datenbanken die Tabelle "Bestellungen".
      Im Online-Shop kommt ein neuer Eintrag(insert) in diese Tabelle, wenn eine neue Bestellung darüber eingeht. Zur gleichen Zeit gibt der Verkäufer im Shop ebenfalls eine neue Bestellung in besagte Tabelle ein, aber lokal in seinem LAN. Wenn jetzt dazwischen keine Synchronisation der beiden Datenbanken stattgefunden hat, haben die ja dieselbe ID, das ist das Kernproblem.

      Damit das nicht passiert, dagegen gibt es im Prinzip nur 2 Wege:

      1. eine Ständige Verbindung, oder eine MasterDB die nur IDs verteilen darf, zu der erst Kontakt aufgenommen werden muß, aber da 2 LANs über T-DSL und eines über ISDN anhebunden sind, also per Dailup, ist das zu unsicher, denn wenn dei Telekom mal wieder Mist baut funktioniert das ganze System nicht mehr und der Betrieb steht still!

      2. Kombination aus eigenen IDs und Standort-IDs, dadurch wird es wieder eindeutig. Hierfür gibt es meines Wissens Primärschlüssel über 2 Spalten, da nur über diese beiden Ids eine Eindeutligkeit des Datensatzes garantiert ist.

      Aber das Problem, wenn man zwei Spalten(Standort-ID, Datensatz-ID) verwendet, dann ändern sich auch alle Zugriffe auf die Datenbank, man kann nicht merh abfragen "WHERE ID =123", man braucht dann "WHERE ID1=12 AND ID2=3232"
      Und das will ich unbedingt vermeiden, indem ich nur eine einzige ID verwende aber eine eigene insert-Funktion baue, die zuerst die Tabelle lockt, danach die höchste ID mit der eigenen StandortID am Anfang ermittelt, diese um 1 erhöht, und in den Query-String schreibt!

      Und da dieser Punkt noch nicht so ganz optimal ist, habe ich den Thread eröffnet, vielleicht hat hier jemand von Euch, der mehr Erfahrung mit Datenbanken hat eine Idee, wie ich das löse.

      Die eigentliche Synchronisation führe ich dann mit curl durch, hiermit übertrage ich die Daten über SSL zum anderen Server, wo ein Script auf die Daten wartet, die neuen Daten schreibt und die eigenen Änderungen ermittelt und zurückschickt. Erst war noch eine GPG-FTP Kombination im Gespräch, nachdem SCP ausgeschieden war, aber die curl-Variante ist wohl die einfachste! Die zu synchronisierenden Daten werden per SQL aus der jeweils lokalen Datenbank ausgelsen.

      Ich hoffe ich habe das verständlich beschrieben, aber ich habe mich soviel damit beschäftigt und so viel probiert, das ich evtl. nicht alles ganz einleuchtend erklärt habe. Würde mich freuen wenn Du eine Idee hast!

      Viele Grüße
      Andreas

      1. Jetzt habe ich z.B. in allen Datenbanken die Tabelle "Bestellungen".
        Im Online-Shop kommt ein neuer Eintrag(insert) in diese Tabelle, wenn eine neue Bestellung darüber eingeht. Zur gleichen Zeit gibt der Verkäufer im Shop ebenfalls eine neue Bestellung in besagte Tabelle ein, aber lokal in seinem LAN. Wenn jetzt dazwischen keine Synchronisation der beiden Datenbanken stattgefunden hat, haben die ja dieselbe ID, das ist das Kernproblem.

        Wäre es denn kein Problem, wenn Du einfach "de facto eindeutige" IDs vergibst, etwa md5(microtime() . $zufallszahl)?

        1. Hi!

          Wäre es denn kein Problem, wenn Du einfach "de facto eindeutige" IDs vergibst, etwa md5(microtime() . $zufallszahl)?

          Gerade das ist ja nicht eindeutig! Gerade wenn das länger verwendet wird rückt der Zeitpunkt immer näher, das sich eine MD5 wiederholt! Außerdem müßte ich dann überall über Strings abfragen, und das soll erheblich lansamer sein als über Integer-Werte!

          Und je mwehr Standorte... desto wahrscheinlicher wird eine Wiederholung! Wenn ich das mache muß das wirklich eindeutig sein, und nicht "eindeutig mit ein wenig Glück" ;-)

          Grüße
          Andreas

      2. Hi Sven!

        die Erste ID könnte ruhig eine Zahl zwischen 1-9 sein, die steht für den Standort, die ander ID ist die autoincrement ID des Datensatzes. Die IDs sollten aber überall gleich sein.

        Die Gefahr besteht, dass sich der Standort ändern kann. Oder dass sich plötzlich mehr als 10 Standorte ergeben. In beiden Fällen würdest du die bislang eindeutige ID verändern bzw. an Grenzen gelangen, die vollkommen unnötig sind.
        Das ist dann mein Problem. Wenn es > 9 Standorte geben sollte mach ich ein Faß auf und besauf mich, zumindest sehe ich zur Zeit (leider) nicht in Ansätzen das die Zahl erreicht wird.

        Da du nicht wirklich "Standorte" hast, sondern im Prinzip nur "Datenbankenstandorte", könnte es ganz schnell passieren, dass du mehr als 9 "Standorte" hast. Jetzt sind es schon 4. Dann gib noch 5 Mitarbeitern einen Laptop für die mobile Datenerfassung in die Hand - 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), und noch zwei Filialen (Nummer 11 und 12)... Naja, es ist jedenfalls Blödsinn, irgendeine Begrenzung einzubauen, die sich irgendwann durch irgendwelche Umstände als außerst störend erweisen könnten - sieh' dir einfach nur das Jahr2000-Problem an!

        Siehe dazu auch http://www.tuxedo.org/~esr/jargon/html/entry/Zero-One-Infinity-Rule.html.

        1. Kombination aus eigenen IDs und Standort-IDs, dadurch wird es wieder eindeutig. Hierfür gibt es meines Wissens Primärschlüssel über 2 Spalten, da nur über diese beiden Ids eine Eindeutligkeit des Datensatzes garantiert ist.

        Aber das Problem, wenn man zwei Spalten(Standort-ID, Datensatz-ID) verwendet, dann ändern sich auch alle Zugriffe auf die Datenbank, man kann nicht merh abfragen "WHERE ID =123", man braucht dann "WHERE ID1=12 AND ID2=3232"
        Und das will ich unbedingt vermeiden, indem ich nur eine einzige ID verwende aber eine eigene insert-Funktion baue, die zuerst die Tabelle lockt, danach die höchste ID mit der eigenen StandortID am Anfang ermittelt, diese um 1 erhöht, und in den Query-String schreibt!

        Warum willst du das Unvermeidliche vermeiden? Du brauchst eine ID zur Identifikation des Datensatzes, und eine ID zur Identifikation der Erfassungsdatenbank - die Kombination beider ist eine systemweit eindeutige ID. Ein SELECT mit zwei Bedingungen ist zwar etwas langsamer als ein SELECT mit nur einer Bedingung - aber immer noch wesentlich schneller, als ein SELECT mit concat() (um die zwei IDs zu verbinden, bevor eine Bedingung wirksam wird).

        Allerdings ist das nicht die einzige Möglichkeit...

        Die eigentliche Synchronisation führe ich dann mit curl durch, hiermit übertrage ich die Daten über SSL zum anderen Server, wo ein Script auf die Daten wartet, die neuen Daten schreibt und die eigenen Änderungen ermittelt und zurückschickt. Erst war noch eine GPG-FTP Kombination im Gespräch, nachdem SCP ausgeschieden war, aber die curl-Variante ist wohl die einfachste! Die zu synchronisierenden Daten werden per SQL aus der jeweils lokalen Datenbank ausgelsen.

        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.

        Mir fallen zwei Methoden ein, die beide dasselbe Prinzip verfolgen.

        1.) Du hast zwei ID-Felder. Eine ID ist die endgültige ID. Diese ID wird vergeben, wenn der Datensatz in die Master-DB eingetragen. Bis es soweit ist, werden in den dezentralen Datenbanken temporäre IDs vergeben.

        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.

        Mit diesem System kannst du anhand der Herkunfts-ID sehen, ob der Datensatz schon zentral gespeichert wurde.

        Ich bin sicher, dass tausend Gründe, die du noch nicht genannt hast, in irgendeiner Weise gegen diese Vorgehensweise sprechen - dann bleibt eben nur die Möglichkeit, ID und Herkunfts-DB einmal beim ersten Erfassen des Datensatzes zu vergeben und immer beizubehalten. Ich würde davon abraten, diese zwei Informationen zu vermischen.

        - Sven Rautenberg

        1. Hallo!

          ... sind mir langsam zu viele Andreas hier im Forum ;-)

          Das ist dann mein Problem. Wenn es > 9 Standorte geben sollte mach ich ein Faß auf und besauf mich, zumindest sehe ich zur Zeit (leider) nicht in Ansätzen das die Zahl erreicht wird.

          Da du nicht wirklich "Standorte" hast, sondern im Prinzip nur "Datenbankenstandorte", könnte es ganz schnell passieren, dass du mehr als 9 "Standorte" hast. Jetzt sind es schon 4. Dann gib noch 5 Mitarbeitern einen Laptop für die mobile Datenerfassung in die Hand -

          da sprichst Du was an - ab MySQL 4.x gibts das so zu sagen als Stand-Alone Client version, das wird interessant...

          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!

          und noch zwei Filialen (Nummer 11 und 12)... Naja, es ist jedenfalls Blödsinn, irgendeine Begrenzung einzubauen, die sich irgendwann durch irgendwelche Umstände als außerst störend erweisen könnten - sieh' dir einfach nur das Jahr2000-Problem an!

          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

          So, das kann ich nach oben ausbauen wie ich will! Das ganze wird regelmäßig nur bei Inserts benötigt, und bei der unregelmäßigen Ermittlung der Daten zur Synchronisation(was natürlich so oft wie möglich passieren soll!)
          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! Man muß sich nur noch über das Szenario Gedanken machen, was denn ist wenn es denn tatsächlich mal dazu kommen sollte, aber das wird man schon lösen! Aber da die Insert-Funktion jeweils zentral nur einmal im Code steht, müßte ich ja nur bei jedem Standort hier was verändern, also halb so wild!

          Aber das Problem, wenn man zwei Spalten(Standort-ID, Datensatz-ID) verwendet, dann ändern sich auch alle Zugriffe auf die Datenbank, man kann nicht merh abfragen "WHERE ID =123", man braucht dann "WHERE ID1=12 AND ID2=3232"
          Und das will ich unbedingt vermeiden, indem ich nur eine einzige ID verwende aber eine eigene insert-Funktion baue, die zuerst die Tabelle lockt, danach die höchste ID mit der eigenen StandortID am Anfang ermittelt, diese um 1 erhöht, und in den Query-String schreibt!

          Warum willst du das Unvermeidliche vermeiden? Du brauchst eine ID zur Identifikation des Datensatzes, und eine ID zur Identifikation der Erfassungsdatenbank - die Kombination beider ist eine systemweit eindeutige ID. Ein SELECT mit zwei Bedingungen ist zwar etwas langsamer als ein SELECT mit nur einer Bedingung - aber immer noch wesentlich schneller, als ein SELECT mit concat() (um die zwei IDs zu verbinden, bevor eine Bedingung wirksam wird).

          von concat() war keine Rede - wieso das? Bei SELECT brauche ich das eben nicht! 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!
          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?

          Allerdings ist das nicht die einzige Möglichkeit...

          die da wären? ;-)

          Ich war insgesamt auf folgende Modelle gekommen
          1. wie beschreiben, eine ID die sich aus Standort_ID und Datensatz-ID zusammensetzt
          2. Master-Server der IDs verteilt, Client-Server haben sowohl eigene IDs, und die des Master
          3. Direkte Anbindung an Master-Server, direkt IDs holen
          4. Nur Master-DB, rest nur Spiegelungen zur Sicherheit

          Die 2. Variante hatte ich zunächst favorisiert, ich hatte das wie folgt geplant:
          Es geht wieder um die Tabelle "Bestellungen" die auf dem Master und den Clients zur Verfügung steht.
          Die Tabellen des Master und der Clients sind fast gleich nur hat der Master die Master-ID mit autoincrement, und Standort-ID als Felder, dafür haben die Clients eine jeweils eigene Client-ID mit autoincrement, und ein Feld Master-ID, die ggfs, bei der Synchronisation zugewiesen wird, oder bei jedem INSERT versucht wird zu bekommen.
          Bei der Synchronisation mit dem Server wird wie gesagt einem neuen Eintrag eines Clients die Master-ID zugewisen, solange hat der nur seine Client-ID. Der Server speichert dafür die Standort-ID, um zu wissen von welchenm Standort das kam (nicht unbedingt notwendig, aber vereinfacht die Synchronisation)

          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!
          Außerdem - wie mache ich das jetzt bei den Clients, welche ID verwende ich hier? die Client-ID? Dann verwende ich als 2 verschiedene IDs für denselben Datensatz, das ist auch nicht gerade gut. Dazu kommt - obwohl ich hier dieselbe Anwendung habe wie auf dem Master, muß ich das Interface speziell programmieren, auch ein erheblicher Nachteil! und es gab noch mehr Probleme  die mir jetzt nicht einfallen...

          Die eigentliche Synchronisation führe ich dann mit curl durch, hiermit übertrage ich die Daten über SSL zum anderen Server, wo ein Script auf die Daten wartet, die neuen Daten schreibt und die eigenen Änderungen ermittelt und zurückschickt. Erst war noch eine GPG-FTP Kombination im Gespräch, nachdem SCP ausgeschieden war, aber die curl-Variante ist wohl die einfachste! Die zu synchronisierenden Daten werden per SQL aus der jeweils lokalen Datenbank ausgelsen.

          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.

          Genau das mache ich auch, das was ich vorhabe ist bis auf die Begrenzung und das ich kein Autoincrement verwenden kann perfekt:
          Ich habe gleiche Tabellen überall, ich habe gleiche IDs überall, das macht das ganze System _erheblich_ einfacher und nicht annährend so Fehleranfällig wie die anderen Varianten!
          Wie oben beschreiben Frage ich beim Synchronisieren und schreiben die höchste ID des eigenen Standortes ab und generiere die neu ID halt selbst. Sollte auch nicht wirklich wild sein.
          Ich synchronisiere immer über den Linix-Server, der beim Provider steht immmer ständig an das Internet angebunden ist. Diesen hätte ich dann auch als Master genommen. Aber dadurch das ich immer über den einen Server abgleiche kann ich einfach den letzten Sync-Zeitpunkt loggen, und alle Datensätze auslesen, deren Timestamp neuer ist, und die schreibe ich dann einfach in die eigene DB. Genau dasselbe umgekehrt, ich logge auch lokal den letzten Sync-Zeitpunkt, alle neuen Datensätze werden zum "Master" übertragen und der trägt das ein. Kein Problem mit Zeitdifferenzen, perfekt.

          Mir fallen zwei Methoden ein, die beide dasselbe Prinzip verfolgen.

          1.) Du hast zwei ID-Felder. Eine ID ist die endgültige ID. Diese ID wird vergeben, wenn der Datensatz in die Master-DB eingetragen. Bis es soweit ist, werden in den dezentralen Datenbanken temporäre IDs vergeben.

          Genau das war mein vorheriger Plan(s.o.), der auch zur Zeit so läuft, aber damit bin ich nicht glücklich.

          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!

          Mit diesem System kannst du anhand der Herkunfts-ID sehen, ob der Datensatz schon zentral gespeichert wurde.

          Ich bin sicher, dass tausend Gründe, die du noch nicht genannt hast, in irgendeiner Weise gegen diese Vorgehensweise sprechen - dann bleibt eben nur die Möglichkeit, ID und Herkunfts-DB einmal beim ersten Erfassen des Datensatzes zu vergeben und immer beizubehalten. Ich würde davon abraten, diese zwei Informationen zu vermischen.

          Das Problem läßt sich darauf herunterbrechen, dass eine eindeutige ID benötigt wird. Das geht solang gut wie ein zentraler Rechner diese Verteilt. Aber sobald ein Standort aus welchem, Grund auch immer darauf keinen Zugriff hat, gibts Probleme. Prinzipiell gibt es 2 Lösungsansätze:
          1. den ID Raum vorher zwischen den Standorten aufteilen
          2. 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.
          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 ;-)

          Viele Grüße
          Andreas

          1. 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

            1. wie beschreiben, eine ID die sich aus Standort_ID und Datensatz-ID zusammensetzt

            Und als schlecht verworfen wurde.

            1. 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.

            1. Direkte Anbindung an Master-Server, direkt IDs holen

            Hattest du schon als undurchführbar beschrieben.

            1. 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.

            1. den ID Raum vorher zwischen den Standorten aufteilen
            2. 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