Generieren einer UUID in Postgres for Insert-Anweisung?

368

Meine Frage ist ziemlich einfach. Ich kenne das Konzept einer UUID und möchte eine generieren, die auf jedes 'Element' aus einem 'Geschäft' in meiner Datenbank mit verweist. Scheint vernünftig, oder?

Das Problem ist, dass die folgende Zeile einen Fehler zurückgibt:

honeydb=# insert into items values(
uuid_generate_v4(), 54.321, 31, 'desc 1', 31.94);
ERROR:  function uuid_generate_v4() does not exist
LINE 2: uuid_generate_v4(), 54.321, 31, 'desc 1', 31.94);
        ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

Ich habe die Seite unter folgender Adresse gelesen: http://www.postgresql.org/docs/current/static/uuid-ossp.html

Geben Sie hier die Bildbeschreibung ein

Ich verwende Postgres 8.4 unter Ubuntu 10.04 x64.

anon58192932
quelle
8
Postgres unterstützt UUID nativ als Datentyp und kann sogar indiziert und als Primärschlüssel verwendet werden. Um jedoch einen UUID-Wert zu generieren , z. B. um einen Standardwert für eine Spalte festzulegen, benötigen Sie eine Postgres-Erweiterung (ein Plugin). Viele Builds (Distributionen) von Postgres enthalten eine solche Erweiterung, aktivieren die Erweiterung jedoch nicht. In der richtigen Antwort von Craig Ringer erfahren Sie, wie Sie sie aktivieren.
Basil Bourque
2
Wenn Sie uuid-ossp installiert haben und dieser Fehler weiterhin auftritt, versuchen Sie, der Funktion Ihren Schemanamen select dbo.uuid_generate_v4()
Richard

Antworten:

435

uuid-osspist ein Contrib-Modul, daher wird es standardmäßig nicht auf den Server geladen. Sie müssen es in Ihre Datenbank laden, um es verwenden zu können.

Für moderne PostgreSQL-Versionen (9.1 und neuer) ist das einfach:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

Für 9.0 und niedriger müssen Sie stattdessen das SQL-Skript ausführen, um die Erweiterung zu laden. Weitere Informationen finden Sie in der Dokumentation zu Contrib-Modulen in 8.4 .

Lesen Sie stattdessen für Seite 9.1 und höher die aktuellen Beiträge und DokumenteCREATE EXTENSION . Diese Funktionen sind in 9.0 oder älteren Versionen wie 8.4 nicht vorhanden.

Wenn Sie eine Paketversion von PostgreSQL verwenden, müssen Sie möglicherweise ein separates Paket installieren, das die Contrib-Module und -Erweiterungen enthält. Durchsuchen Sie Ihre Paketmanager-Datenbank nach "Postgres" und "Contrib".

Craig Ringer
quelle
6
@advocate Sie verwenden ein in einer Distribution verpacktes PostgreSQL, sodass Sie in der Lage sein sollten, genau apt-get install postgresql-contriboder ähnlich zu arbeiten. Versuchen apt-cache search postgresql |grep contribSie, den gewünschten Paketnamen zu finden.
Craig Ringer
2
sudo apt-get install postgresql-contrib wurde erfolgreich ausgeführt. Dann musste ich psql -d dbname -f SHAREDIR / contrib / module.sql ausführen und jetzt funktioniert es !!! wähle uuid_generate_v1 (); gibt jetzt 1 zurück. Vielen Dank!
anon58192932
5
Beachten Sie, dass wenn Sie das postgresql-contribPaket nicht installieren , die folgende Fehlermeldung angezeigt
Drew Noakes
1
Ich habe diesen Kommentar gepostet, als die Fehlerzeichenfolge bei Google durchgestrichen wurde. Außerdem gibt es einen bestimmten Paketnamen, zumindest für Ubuntu.
Drew Noakes
2
Wenn Sie eine Datenbank importiert haben, deren uuid-ossp bereits in den Erweiterungen enthalten ist, funktioniert uuid_generate_v4 () möglicherweise nicht. Wenn dies der Fall ist, entfernen Sie einfach die Erweiterung und erstellen Sie sie erneut. Es sollte funktionieren.
Dragos Rusu
302

Ohne Erweiterungen (Cheat)

SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring);

output>> c2d29867-3d0b-d497-9191-18a9d8ee7830

(funktioniert mindestens in 8.4)

  • Vielen Dank an @Erwin Brandstetter für die clock_timestamp()Erklärung.

Wenn Sie eine gültige v4-UUID benötigen

SELECT uuid_in(overlay(overlay(md5(random()::text || ':' || clock_timestamp()::text) placing '4' from 13) placing to_hex(floor(random()*(11-8+1) + 8)::int)::text from 17)::cstring);

Geben Sie hier die Bildbeschreibung ein * Danke an @Denis Stafichuk @Karsten und @autronix


In modernen Postgres können Sie auch einfach Folgendes besetzen:

SELECT md5(random()::text || clock_timestamp()::text)::uuid

ZuzEL
quelle
5
Um Ihre PS zu verfolgen: SELECTuuid_in(md5(random()::text || now()::text)::cstring);
Blaskovicz
4
@MattDiPasquale Wahrscheinlich in keiner Weise "besser" als die Verwendung uuid-ossp, aber ich arbeite zum Beispiel an einer PostgreSQL-Instanz, bei der ich nicht über die erforderlichen Berechtigungen zum Installieren einer Erweiterung verfüge .
Stefan Haberl
25
@ JosephLennox: clock_timestamp()ist in jedem Fall die bessere Alternative dafür. Im Gegensatz zu now()oder ist CURRENT_TIMESTAMPes volatil und gibt die aktuelle Uhrzeit zurück. SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring);In modernen Postgres können Sie auch einfach Folgendes wirken: SELECT md5(random()::text || clock_timestamp()::text)::uuid- Keine Notwendigkeit für mehr Magie. Anwendungsfall: stackoverflow.com/a/8335376/939860
Erwin Brandstetter
17
Nee. Wenn das überhaupt funktioniert, ist es reines Glück. Eine UUID hat ein Format, bei dem nicht nur zufällige Hex-Zeichen zusammengewürfelt werden. Die erste Nummer der 3. Gruppe ist die UUID-Version für Intance (heutzutage normalerweise 4). Wenn Ihre Anwendung diese Ziffer überprüft, um festzustellen, mit welcher Version von uuid sie sich befasst, und etwas entsprechend unternimmt, schlägt Ihr Code fehl.
Tuncay Göncüoğlu
7
@Tuncay Göncüoğlu: Es ist ziemlich einfach, eine gültige v4-UUID zu generieren (der String-Overlay-Ansatz verschwendet jedoch 2 Bits Zufälligkeit):select overlay(overlay(md5(random()::text || ':' || clock_timestamp()::text) placing '4' from 13) placing '8' from 17)::uuid;
Karsten
75

Die Antwort von Craig Ringer ist richtig. Hier ein paar Infos zu Postgres 9.1 und höher…

Ist eine Erweiterung verfügbar?

Sie können eine Erweiterung nur installieren, wenn sie bereits für Ihre Postgres-Installation erstellt wurde (Ihr Cluster in Postgres-Jargon). Zum Beispiel fand ich die Erweiterung uuid-ossp, die im Installationsprogramm für Mac OS X enthalten ist und freundlicherweise von EnterpriseDB.com bereitgestellt wird. Jede von ein paar Dutzend Erweiterungen verfügbar sein.

Führen Sie diese SQL aus, um den Systemkatalog abzufragen, um festzustellen, ob die Erweiterung uuid-ossp in Ihrem Postgres-Cluster verfügbar ist pg_available_extensions:

SELECT * FROM pg_available_extensions;

Installation installieren

Verwenden Sie zum Installieren dieser UUID- bezogenen Erweiterung den Befehl CREATE EXTENSION, wie in dieser SQL dargestellt:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

Achtung: Ich habe festgestellt, dass die QUOTATION MARK-Zeichen um den Erweiterungsnamen trotz gegenteiliger Dokumentation erforderlich sind.

Das SQL-Standardkomitee oder das Postgres-Team haben einen ungeraden Namen für diesen Befehl gewählt. Meiner Meinung nach hätten sie etwas wie "INSTALL EXTENSION" oder "USE EXTENSION" wählen sollen.

Überprüfen Sie die Installation

Sie können überprüfen, ob die Erweiterung erfolgreich in der gewünschten Datenbank installiert wurde, indem Sie diese SQL ausführen, um den pg_extensionSystemkatalog abzufragen :

SELECT * FROM pg_extension;

UUID als Standardwert

Weitere Informationen finden Sie in der Spalte Frage: Standardwert für UUID in Postgres

Der alte Weg

Die oben genannten Informationen verwenden die neuen Erweiterungen Feature hinzugefügt , um Postgres 9.1. In früheren Versionen mussten wir ein Skript in einer SQL- Datei finden und ausführen . Die Erweiterungsfunktion wurde hinzugefügt, um die Installation zu vereinfachen und dem Ersteller einer Erweiterung etwas mehr Arbeit gegen weniger Arbeit seitens des Benutzers / Verbrauchers der Erweiterung einzutauschen. Weitere Diskussionen finden Sie in meinem Blogbeitrag .

Arten von UUIDs

Der Code in der Frage ruft übrigens die Funktion auf uuid_generate_v4(). Dies erzeugt einen als Version 4 bekannten Typ, bei dem fast alle 128 Bits zufällig erzeugt werden. Während dies für die eingeschränkte Verwendung in kleineren Zeilengruppen in Ordnung ist, verwenden Sie eine andere "Version" von UUID, wenn Sie die Möglichkeit einer Kollision praktisch ausschließen möchten.

Beispielsweise kombiniert die ursprüngliche Version 1 die MAC-Adresse des Host-Computers mit dem aktuellen Datum und der Uhrzeit und einer beliebigen Zahl. Die Wahrscheinlichkeit von Kollisionen ist praktisch gleich Null.

Weitere Informationen finden Sie in meiner Antwort auf die zugehörige Frage.

Basil Bourque
quelle
1
Und Sie können auch verwenden, CREATE EXTENSION IF NOT EXISTS ...wenn Sie nicht sicher sind und nicht überprüfen möchten (in einem Skript zB)
Uwe Allner
2
UUIDs der Version 4 eignen sich für Datensätze nahezu jeder Größe, nicht nur für "eingeschränkte Verwendung bei kleineren Zeilengruppen". Sie müssten ungefähr 85 Jahre lang 1 Milliarde UUIDs pro Sekunde generieren (oder ungefähr 45 Millionen Terabyte Daten, tausende Male größer als die größten Datenbanken von heute), um überhaupt eine 50% ige Kollisionswahrscheinlichkeit zu haben. Sofern Sie nicht die NSA sind, ist Version 4 für jeden Zweck in Ordnung. Version 1 litt dagegen unter der Tatsache, dass MAC-Adressen nacheinander zugewiesen werden (und häufig gefälscht oder nicht verfügbar sind), was ein Teil der Gründe ist, warum spätere Versionen eingeführt wurden.
Jazz
1
@BasilBourque Das Problem mit v1 ist nicht die Wahrscheinlichkeit einer Kollision bei korrekter Implementierung, sondern die Wahrscheinlichkeit einer falschen Implementierung. Wie Wikipedia es ausdrückt: "Die Einzigartigkeit von UUIDs der Versionen 1 und 2 ... hängt auch davon ab, dass Netzwerkkartenhersteller ihren Karten ordnungsgemäß eindeutige MAC-Adressen zuweisen, was wie bei anderen Herstellungsverfahren fehleranfällig ist." In einigen containerisierten oder virtualisierten Umgebungen sind echte MAC-Adressen von der zugrunde liegenden Hardware nicht verfügbar. Wenn viele Container denselben MAC haben, aber ihre eigenen Clockseq-Zähler, können ihre v1-UUIDs kollidieren.
Jazz
1
@BasilBourque Schwächen in v1 sind jedoch nicht der Hauptpunkt meines Kommentars. Ihre ursprüngliche Antwort impliziert, dass v4 aufgrund einer höheren Kollisionswahrscheinlichkeit als v1 nicht für große Datenmengen geeignet ist. Dies ist irreführend und möglicherweise falsch, obwohl es schwierig ist, die Kollisionswahrscheinlichkeit für v1 zu berechnen, da sie so implementierungsabhängig ist.
Jazz
1
@BasilBourque Das Node-UUID-Projekt berechnet beispielsweise die Wahrscheinlichkeit, dass ihre Clockseq-Zähler gleich sind (sodass zwei Prozesse dieselbe Sequenz von v1-UUIDs generieren würden) wie 1 in 4.6e18. Dies ist zwar winzig, aber viel wahrscheinlicher als die Wahrscheinlichkeit einer sofortigen Kollision in Version 4, die 1 in 5.3e36 beträgt. Je länger Sie v4-UUIDs generieren, desto wahrscheinlicher wird eine Kollision. Dies gilt natürlich nicht für v1. Sie müssten jedoch 1,52 Milliarden v4-UUIDs generieren, bevor die Wahrscheinlichkeit einer Kollision die der v1-Implementierung des Knotens überschreitet. Die meisten Leute haben nicht 1,52 Milliarden Datensätze pro Tabelle.
Jazz
61

pgcrypto Erweiterung

Ab Postgres 9.4 enthält das pgcryptoModul die gen_random_uuid()Funktion. Diese Funktion generiert einen auf Zufallszahlen basierenden UUID-Typ der Version 4 .

Holen Sie sich Contrib-Module, falls nicht bereits verfügbar.

sudo apt-get install postgresql-contrib-9.4

Verwenden pgcryptoModul.

CREATE EXTENSION "pgcrypto";

Die gen_random_uuid()Funktion sollte jetzt verfügbar sein.

Anwendungsbeispiel.

INSERT INTO items VALUES( gen_random_uuid(), 54.321, 31, 'desc 1', 31.94 ) ;


Zitat aus dem Postgres-Dokument zumuuid-ossp Modul.

Hinweis: Wenn Sie nur zufällig generierte (Version 4) UUIDs benötigen, sollten Sie stattdessen die Funktion gen_random_uuid () aus dem pgcrypto-Modul verwenden.

Brillout
quelle
3
Ja, aber siehe auch blog.starkandwayne.com/2015/05/23/…, wo sie vor Fragmentierung warnen und stattdessen uuid-ossp vorschlagen.
Malik A. Rumi
3
Siehe postgresql.org/message-id/…, wo das Problem der UUID-Fragmentierung in Postgres entlarvt wird
Bob Kocisko
Aber postgres hat in der neuesten Version Clustered-Indizes, was den im obigen Kommentar verknüpften Beitrag nicht schlüssig und falsch macht, und wir sind gleich wieder auf Platz 1.
Michael Goldshteyn
1
@ MichaelGoldshteyn: Nein, Postgres hat keine Clustered-Indizes (ab Postgres 12)
a_horse_with_no_name
3
ALTER TABLE table_name ALTER COLUMN id SET DEFAULT uuid_in((md5((random())::text))::cstring);

Nachdem ich die Antwort von @ ZuzEL gelesen hatte, verwendete ich den obigen Code als Standardwert für die Spalten-ID und es funktioniert einwandfrei.

Paolo Fernandes
quelle
1

Das kommende PostgreSQL 13 unterstützt nativ gen_random_uuid (), ohne dass Erweiterungen aktiviert werden müssen:

PostgreSQL enthält eine Funktion zum Generieren einer UUID:

gen_random_uuid ()  uuid

Diese Funktion gibt eine (zufällige) UUID der Version 4 zurück. Dies ist der am häufigsten verwendete UUID-Typ und für die meisten Anwendungen geeignet.

db <> Geigen-Demo

Lukasz Szozda
quelle