Konventierung von UUID4 in Integer

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Hallo Leute,

es ist ja in Python in nur einer Zeile möglich, dass man aus deinem UUID einen Integer erzeugen kann:


[Codebox=python file=Unbenannt.py]
import uuid
print "Converted UUID to Integer:", uuid.uuid4().int
[/Codebox]



Allerdings habe ich hier eine Frage: Dieser erzeugte Integer wäre dann nicht mehr weltweit eindeutig, richtig? Ich schätze eher nicht. Warum ich das Frage? In meinem Projekt hatte ich ursprünglich vor UUIDs als primäre IDs zu verwenden. Ich weiß aber auch, dass UUIDs als String gelten. Und das Vergleichen von zwei String ist vom Rechenaufwand her wesentlich höher als wenn man zwei Zahlen (Integer) miteinander vergleich. Ich möchte also den MySQL-Server schonen und etwas entgegenkommen. Nun kam ich durch Zufall auf diesen Skript. An sich eine gute und verlockende Idee. Aber ich dachte mir, dass durch die Konvertierung die Eindeutigkeit eines UUIDs verloren geht.

EDIT: Ist das Forum nun kaputt oder wieso wird das Skript nicht richtig formatiert?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Sophus: UUIDs sind 128bit an Information. Python hat mit großen Integern keine Probleme, bei Deiner Datenbank sieht das je nach Typ aber anders aus. Das was Du vorhast geht einfach und schlicht nicht. Viele Datenbanken haben aber einen speziellen UUID-Typ. Dein Versuch auf der einen Seite etwas kompliziert zu machen, damit irgendwo vielleicht Deinem Gefühl nach etwas schneller geht, ... vergiß es. Schreib so einfach und klar wie möglich Deine Programme. Erst wenn es wirklich Probleme mit der Geschwindigkeit gibt, kannst Du nach Verbesserungen suchen. UUID wird dabei aber garantiert nicht das Problem sein.
BlackJack

@Sophus: Wieso sollte die Eindeutigkeit verloren gehen? Also mal davon abgesehen das die sowieso nicht garantiert, sondern nur recht wahrscheinlich ist bei UUID4.

Code: Alles auswählen

In [17]: x = uuid.uuid4()

In [18]: x
Out[18]: UUID('2ee370fb-2479-40e8-95dd-40efcc0f4d92')

In [19]: x.int
Out[19]: 62325430720425982992327945753614830994L

In [20]: uuid.UUID(int=x.int)
Out[20]: UUID('2ee370fb-2479-40e8-95dd-40efcc0f4d92')

In [21]: uuid.UUID(int=x.int) == x
Out[21]: True
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@Sirius3: Ich bin leider nicht schlau aus deiner Ausführung geworden. Was meinst du mit kompliziert? Und was soll ich genau vergessen? Du meinst, die Datenbank hat ein Problem damit, eine 32 stellige Zahl (nach der Konvertierung eines UUIDs) als primäre ID zu nehmen?

Meine Überlegung sah wie folgt aus: Es ist ja möglich, dass man nach dem Abspeichern eines Datensatz von der Datenbank (Typ der Datenbank ist mal egal) die ID bekommt, die die Datenbank selbst generiert hat. Ich wollte aber den Weg nicht gehen, dass ich erst nach dem Abspeichern eines Datensatzes die ID zur Sicht bekomme. Also überlegte ich mir, wie es möglich wäre weiter vorher, also vor dem Abspeichern, mit einer ID arbeiten kann. Da fiel mir die uuid4 ein. Soweit so gut. Aber ich habe mich ein wenig schlau gemacht. Es ist in vielen Foren die Rede, dass das Verwenden von UUIDs mehr Nachteile bringt als Vorteile. Unter anderen wurde da auch der enorme Geschwindigkeitsverlust angeführt. Also suchte ich nach einen anderen Weg, und kam durch Zufall auf ein Forum, wo jemand meinte, man könnte die UUID in ein Integer umwandeln. Nun haben wir hier nicht mehr mit einem String (UUID) zutun, sondern mit einem Integer. Und auf dieser Basis ging ich davon aus, dass eine Datenbank dadurch keine Geschwindigkeitsverluste aufzeigt.

Mir geht es also nicht um das Programm Python, sondern um die Datenbank.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Sophus: ah, ok. Du hast ganz am Anfang einen Denkfehler. Die primary-key-ID wird am besten von der Datenbank erzeugt und nicht von Dir. Warum willst Du sie denn vorher haben?
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@Sirius: Warum ich eine ID selbst erzeugen möchte? Ganz einfach, weil das Verarbeiten der noch nicht abgespeicherten Datensätze wesentlich einfacher ist. Ich arbeite nicht mit einer Tabelle, sondern reichlich viele, die alle in Beziehung zueinander stehen. Dementsprechend kannst du dir vorstellen, dass man viele Informationen zu einem Datensatz abspeichern kann. Alles soweit kein großes Ereignis. Nun wollte ich aber nicht den Umweg gehen, erst einen bestimmten Datensatz abzuspeichern, dann der Datenbank mitteilen, sie möge mir doch bitte die ID geben, dann die ID geben lassen und dann mit den restlichen Informationen weiterarbeiten. Um das mal klarer zu machen.

Beispiel: Stell dir einen Film vor, zu einem Film gibt es viele Schauspieler, eine lange Liste. Nach meinem Weg müsste ich erst einmal den Film abspeichern, bekomme dann die ID vom eben abgespeicherten Film, und kann dann die Schauspieler (restliche Informationen) zum Film zuordnen. Viel zu umständlich. So erzeuge ich doch gleich zu Beginn, bevor der Anwender den Film abspeichert, eine ID, und wenn der Anwender den Film und die dazugehörigen Schauspieler abspeichert, wird alles gleich in einem Rutsch erledig, denn die ID habe ich schon, und erspare mir den Zwischenschritt.
BlackJack

@Sophus: Ich sehe nicht wo das normale Vorgehen umständlich sein soll. Ich finde eher Dein Vorgehen sich selber um die ID zu kümmern, und dann auch noch auf diese Art, viel umständlicher. Die UUID ist unnötig gross und vor allem bei UUID4 auch gar nicht garantiert eindeutig. Die Gefahr ist zwar relativ gering, aber trotzdem: warum das Risiko eingehen, wenn es doch sicher, schneller, und was die Datengrösse angeht auch kleiner geht‽ Der ”Zwischenschritt” ist nach dem INSERT das `lastrowid`-Attribut vom Cursor-Objekt abzufragen.

Wenn Du es leichter haben möchtest, verwende ein ORM das sich um die IDs von noch nicht gespeicherten Datensätzen kümmert.

Edit:

Code: Alles auswählen

# ...
    cursor.execute('INSERT INTO movie (name, year) VALUES (?, ?)', (name, year))
    movie_id = cursor.lastrowid
    for actor_id in actor_ids:
        cursor.execute(
            'INSERT INTO movie_actor (movie_id, actor_id) VALUES (?, ?)',
            (movie_id, actor_id)
        )
    connection.commit()
Oder mit einem ORM:

Code: Alles auswählen

# ...
    session.add(Movie(name=name, year=year, actors=actors))
    session.commit()
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Sophus: Ich würd's nicht empfehlen. Der Geschwindigkeitsvorteil, dass man vielleicht ein Statement zum Abfragen der generierten ID einspart, ist gering. Der Nachteil ist, dass potenzielle Optimierungen des DBMS verloren gehen. Zudem verbraucht das Abspeichern der UUID oder eines daraus erzeugten Integers in der Regel mehr Speicher im Vergleich zu einer generierten ID. Das bläht den Index unnötig auf und kann sich gerade bei großen Datenmengen als Nachteil entpuppen.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Jetzt weiß ich wieder, weshalb ich meine IDs selbst kreieren wollte. Der Grund war, dass ich später in meinem Programm die Möglichkeit einräume, dass man zum Beispiel alle Datensätze (dazu auch die IDs der jeweiligen Datensätze) aus der MySQL-Datenbank nach SQLite (oder auch andersrum) transportieren bzw. kopieren kann. Wenn ich aber der jeweiligen Datenbank überlasse selbst IDs zu erzeugen, indem ich sage, die Felder sollen die Eigenschaft "Primary Key" haben und das auch mit "Auto Increment" bestücke, dann wird das schwierig. Man stelle sich das vor, in der MySQL- und in der SQLLite-Datenbank werden IDs von den Datenbanken aus generiert, dann stelle ich es mir sehr umständlich vor, wenn ich versuche die Datensätze (mit den dazugehörigen IDs) von der einen Datenbank in die andere Datenbank zu kopieren. Dann die Datenbank (sagen wir mal SQLite), in die die Daten kopiert werden, generiert wieder ihre eigenen ID oder würden dann meckern.
BlackJack

@Sophus: Ich sehe nicht wieso da irgendwas schwierig werden sollte. Ich denke Du siehst Probleme wo keine sind, schaffst Dir aber mit Deiner ”Lösung” neue, Reale, oder aber zumindest unnötigen Mehraufwand.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@BlackJack: Schwierig vielleicht nicht, aber eher umständlich oder? Angenommen, ich will Datensätze von der MySQL-Datenbank nach der SLQite-Datenbank kopieren. Zunächst einmal wird eine SQLite-Datenbank mit den benötigten Tabellen, Feldern, und die Eigenschaften der Felder erzeugt. In diesem Schritt werden die ID-Felder in der SQLite-Datenbank dann mit Primary Key typisiert, korrekt? Und wenn ich jetzt Datensätze von MySQL nach SQLite (wohl gemerkt, die dazugehörigen IDs auch), dann denke ich, kann die SQLite-Datenbank erst einmal meckern. Immerhin versucht die SQLite-Datenbank ja selbst IDs zu generieren.
BlackJack

@Sophus: Wenn Du die IDs mit einträgst, warum sollte die Datenbank dann ”meckern”? Nach der Logik könnte man ja nicht einmal mit dem selben DBMS eine Sicherung anlegen und später wieder einspielen. Die ID wird nur automatisch vergeben wenn beim anlegen des Datensatzes keine angegeben wurde.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Du versuchst Lösungen für Probleme zu finden von denen du noch nichtmal weisst ob sie existieren. Das ist Zeitverschwendung, schlechtes Design und führt zu unnötiger Komplexität. Du solltest dass grundsätzlich nicht tun.

Konkret in diesem Fall existiert das Problem was du siehst auch gar nicht. Wenn du die ID angibst wird die übernommen, vorrausgesetzt der implizite Unique Constraint wird nicht verletzt.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

BlackJack: Ich ging davon aus, dass eine jede Datenbank bei einem Primary Key hingeht und sagt "Ich lege hier die IDs an, und niemand sonst". Dann habe ich das Ganze etwas Falsch verstanden.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

primary key != autoincrement.

Der Primärschlüssel (PK) dient zur eindeutigen Identifizierung eines Eintrags in die DB. Wer den PK anlegt und wie dieser gestaltet ist (einfacher Integer Wert, composite primary key etc) ist damit nicht festegelegt.

Noch zwei Links zum Weiterlesen:
* http://www.tutorialspoint.com/sql/sql-primary-key.htm
* https://de.wikipedia.org/wiki/Schl%C3%B ... .C3.BCssel

Gruß, noisefloor
Antworten