Vous générez un UUID dans Postgres pour l'insertion?

368

Ma question est assez simple. Je connais le concept d'un UUID et je veux en générer un pour faire référence à chaque 'article' d'un 'magasin' dans ma base de données avec. Semble raisonnable non?

Le problème est que la ligne suivante renvoie une erreur:

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.

J'ai lu la page sur: http://www.postgresql.org/docs/current/static/uuid-ossp.html

entrez la description de l'image ici

J'utilise Postgres 8.4 sur Ubuntu 10.04 x64.

anon58192932
la source
8
Postgres prend en charge nativement l' UUID en tant que type de données, même capable d'être indexé et utilisé comme clé primaire. Mais pour générer une valeur UUID, par exemple pour établir une valeur par défaut pour une colonne, vous avez besoin d'une extension Postgres (un plugin). De nombreuses versions (distributions) de Postgres incluent une telle extension mais n'activent pas l'extension. Voir la bonne réponse de Craig Ringer pour savoir comment l'activer.
Basil Bourque
2
Si uuid-ossp est installé et que vous obtenez toujours cette erreur, essayez de préfixer la fonction avec le nom de votre schéma, par exempleselect dbo.uuid_generate_v4()
Richard

Réponses:

435

uuid-osspest un module contrib, il n'est donc pas chargé sur le serveur par défaut. Vous devez le charger dans votre base de données pour l'utiliser.

Pour les versions PostgreSQL modernes (9.1 et plus récentes), c'est simple:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

mais pour la version 9.0 et inférieure, vous devez plutôt exécuter le script SQL pour charger l'extension. Voir la documentation des modules contrib au 8.4 .

Pour Pg 9.1 et plus récent, lisez plutôt les documents de contribution actuels et CREATE EXTENSION. Ces fonctionnalités n'existent pas dans les versions 9.0 ou antérieures, comme votre 8.4.

Si vous utilisez une version packagée de PostgreSQL, vous devrez peut-être installer un package séparé contenant les modules contrib et les extensions. Recherchez dans la base de données de votre gestionnaire de paquets «postgres» et «contrib».

Craig Ringer
la source
6
@advocate Vous utilisez un PostgreSQL distribué par distribution, vous devriez donc être en mesure de simplement apt-get install postgresql-contribou similaire. Essayez apt-cache search postgresql |grep contribde trouver le nom de package souhaité.
Craig Ringer
2
sudo apt-get install postgresql-contrib s'est exécuté avec succès. Ensuite, j'ai dû exécuter psql -d dbname -f SHAREDIR / contrib / module.sql et maintenant cela fonctionne !!! sélectionnez uuid_generate_v1 (); renvoie 1 maintenant maintenant. Merci beaucoup!
anon58192932
5
Notez que si vous n'installez pas le postgresql-contribpackage, vous obtiendrez l'erreur: ERREUR: impossible d'ouvrir le fichier de contrôle d'extension "/usr/share/postgresql/9.3/extension/uuid-ossp.control": aucun fichier ou répertoire de ce type
Drew Noakes du
1
J'ai publié ce commentaire lorsque la chaîne d'erreur a été supprimée sur Google. Il donne également un nom de package spécifique, pour Ubuntu au moins.
Drew Noakes du
2
Si vous avez déjà importé une base de données qui contient déjà uuid-ossp dans les extensions, uuid_generate_v4 () peut ne pas fonctionner. Si tel est le cas, supprimez simplement l'extension, puis créez-la à nouveau et cela devrait fonctionner.
Dragos Rusu
304

Sans extensions (triche)

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

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

(fonctionne au moins en 8.4)

  • Merci à @Erwin Brandstetter pour ses clock_timestamp()explications.

Si vous avez besoin d'un UUID v4 valide

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);

entrez la description de l'image ici * Merci à @Denis Stafichuk @Karsten et @autronix


De plus, dans Postgres moderne, vous pouvez simplement lancer:

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

ZuzEL
la source
5
Pour suivre votre PS: SELECTuuid_in(md5(random()::text || now()::text)::cstring);
Blaskovicz
4
@MattDiPasquale Probablement pas du tout "meilleur" que d'utiliser uuid-ossp, mais je travaille par exemple sur une instance PostgreSQL où je n'ai pas les privilèges suffisants pour installer une extension.
Stefan Haberl
25
@JosephLennox: clock_timestamp()est la meilleure alternative dans les deux cas pour cela. Contrairement à now()ou CURRENT_TIMESTAMPil est volatil et renvoie l'heure actuelle réelle. SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring);De plus, dans les Postgres modernes, vous pouvez simplement lancer: SELECT md5(random()::text || clock_timestamp()::text)::uuid- pas besoin de plus de magie. Cas d'utilisation: stackoverflow.com/a/8335376/939860
Erwin Brandstetter
17
Nan. Si cela fonctionne, c'est sa chance. un UUID a un format, ses caractères hexadécimaux non seulement jetés ensemble.Le premier numéro du 3e groupe est la version uuid pour intance (généralement 4 de nos jours). Si votre application vérifie ce chiffre pour voir avec quelle version d'uuid elle traite et fait quelque chose en conséquence, elle échouera dans votre code.
Tuncay Göncüoğlu
7
@Tuncay Göncüoğlu: Il est assez simple de générer un UUID v4 valide (l'approche de superposition de chaînes gaspille cependant 2 bits d'aléatoire):select overlay(overlay(md5(random()::text || ':' || clock_timestamp()::text) placing '4' from 13) placing '8' from 17)::uuid;
Karsten
75

La réponse de Craig Ringer est correcte. Voici un peu plus d'informations sur Postgres 9.1 et versions ultérieures…

L'extension est-elle disponible?

Vous ne pouvez installer une extension que si elle a déjà été construite pour votre installation Postgres (votre cluster dans le jargon Postgres). Par exemple, j'ai trouvé l' extension uuid-ossp incluse dans le cadre du programme d'installation pour Mac OS X gracieusement fourni par EnterpriseDB.com. L'une des quelques dizaines d'extensions peut être disponible.

Pour voir si l' extension uuid-ossp est disponible dans votre cluster Postgres, exécutez ce SQL pour interroger le pg_available_extensionscatalogue système:

SELECT * FROM pg_available_extensions;

Installer l'extension

Pour installer cette extension UUID , utilisez la commande CREATE EXTENSION comme indiqué dans ce SQL:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

Attention: j'ai trouvé que les caractères MARQUE DE CITATION autour du nom de l'extension étaient requis, malgré la documentation contraire.

Le comité des normes SQL ou l'équipe Postgres a choisi un nom étrange pour cette commande. À mon avis, ils auraient dû choisir quelque chose comme "INSTALLER UNE EXTENSION" ou "UTILISER UNE EXTENSION".

Vérifier l'installation

Vous pouvez vérifier que l'extension a été correctement installée dans la base de données souhaitée en exécutant ce SQL pour interroger le pg_extensioncatalogue système:

SELECT * FROM pg_extension;

UUID comme valeur par défaut

Pour plus d'informations, voir la colonne Question: Valeur par défaut de l'UUID dans Postgres

The Old Way

Les informations ci-dessus utilisent la nouvelle fonctionnalité Extensions ajoutée à Postgres 9.1. Dans les versions précédentes, nous devions trouver et exécuter un script dans un fichier .sql . La fonctionnalité Extensions a été ajoutée pour faciliter l'installation, échangeant un peu plus de travail pour le créateur d'une extension contre moins de travail de la part de l'utilisateur / consommateur de l'extension. Voir mon article de blog pour plus de discussion.

Types d'UUID

Soit dit en passant, le code de la question appelle la fonction uuid_generate_v4(). Cela génère un type connu sous le nom de version 4 où presque tous les 128 bits sont générés de manière aléatoire. Bien que cela soit bien pour une utilisation limitée sur un plus petit ensemble de lignes, si vous voulez éliminer pratiquement toute possibilité de collision, utilisez une autre "version" d'UUID.

Par exemple, la version originale 1 combine l' adresse MAC de l'ordinateur hôte avec la date-heure actuelle et un nombre arbitraire, le risque de collisions est pratiquement nul.

Pour plus de discussion, voir ma réponse à une question connexe.

Basil Bourque
la source
1
Et vous pouvez également utiliser CREATE EXTENSION IF NOT EXISTS ...si vous n'êtes pas sûr et que vous ne voulez pas vérifier (dans un script par exemple)
Uwe Allner
2
Les UUID de la version 4 conviennent à presque tous les ensembles de données de taille, pas seulement à "une utilisation limitée sur des ensembles de lignes plus petits". Vous devriez générer 1 milliard d'UUID par seconde pendant environ 85 ans (ou environ 45 millions de téraoctets de données, des milliers de fois plus grandes que les plus grandes bases de données aujourd'hui) pour même avoir 50% de chances de collision. Sauf si vous êtes la NSA, la version 4 convient parfaitement à n'importe quel but. La version 1, en revanche, souffrait du fait que les adresses MAC sont attribuées séquentiellement (et sont souvent usurpées ou indisponibles), ce qui explique en partie pourquoi des versions ultérieures ont été introduites.
Jazz
1
@BasilBourque Le problème avec la v1 n'est pas la probabilité de collision lorsqu'elle est correctement implémentée, c'est la probabilité d'une implémentation incorrecte. Comme le dit Wikipedia: "L'unicité des UUID des versions 1 et 2 ... dépend également des fabricants de cartes réseau attribuant correctement des adresses MAC uniques à leurs cartes, qui, comme les autres processus de fabrication, sont sujettes à erreur." De plus, dans certains environnements conteneurisés ou virtualisés, les vraies adresses MAC du matériel sous-jacent ne sont pas disponibles. Si de nombreux conteneurs ont le même MAC mais leurs propres compteurs d'horloge, leurs UUID v1 peuvent entrer en collision.
Jazz
1
@BasilBourque Les faiblesses de la v1 ne sont cependant pas le point principal de mon commentaire. Votre réponse originale implique que v4 ne convient pas aux grands ensembles de données en raison d'une probabilité de collision plus élevée que v1. Ceci est trompeur et peut-être faux, bien qu'il soit difficile de calculer la probabilité de collision pour v1 car elle dépend tellement de l'implémentation.
Jazz
1
@BasilBourque Par exemple, le projet node-uuid calcule la probabilité que leurs compteurs clockseq soient identiques (de sorte que deux processus génèrent la même séquence d'UUID v1) que 1 dans 4.6e18. C'est minuscule, oui, mais beaucoup plus probable que le risque de collision immédiate en v4, qui est de 1 sur 5.3e36. Évidemment, plus vous générez des UUID v4 plus longtemps, plus une collision devient probable, ce qui n'est pas le cas de la v1, mais vous devez générer 1,52 milliard d'UUID v4 avant que la probabilité de collision ne dépasse celle de l'implémentation v1 du nœud. La plupart des gens n'ont pas 1,52 milliard d'enregistrements par table.
Jazz
61

pgcrypto Extension

Depuis Postgres 9.4, le pgcryptomodule comprend lesgen_random_uuid() fonction. Cette fonction génère l'un des UUID de type version 4 basés sur des nombres aléatoires .

Obtenez les modules contrib, s'ils ne sont pas déjà disponibles.

sudo apt-get install postgresql-contrib-9.4

Utilisez le pgcryptomodule.

CREATE EXTENSION "pgcrypto";

La gen_random_uuid()fonction devrait maintenant être disponible;

Exemple d'utilisation.

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


Citation du document Postgres sur leuuid-ossp module.

Remarque: Si vous n'avez besoin que d'UUID générés aléatoirement (version 4), envisagez plutôt d'utiliser la fonction gen_random_uuid () du module pgcrypto.

éclat
la source
3
Oui, mais voir aussi blog.starkandwayne.com/2015/05/23/… où ils mettent en garde contre la fragmentation et suggèrent uuid-ossp à la place.
Malik A. Rumi
3
En fait, voir postgresql.org/message-id/… où le problème de fragmentation uuide dans Postgres est démystifié
Bob Kocisko
Mais postgres a des index clusterisés dans la dernière version, ce qui rend le message lié dans le commentaire ci-dessus peu concluant et incorrect et nous sommes de retour à la case 1.
Michael Goldshteyn
1
@MichaelGoldshteyn: non, Postgres n'a pas d'index clusterisés (à partir de Postgres 12)
a_horse_with_no_name
3
ALTER TABLE table_name ALTER COLUMN id SET DEFAULT uuid_in((md5((random())::text))::cstring);

Après avoir lu la réponse de @ ZuzEL, j'ai utilisé le code ci-dessus comme valeur par défaut de l'id de la colonne et cela fonctionne bien.

Paolo Fernandes
la source
1

PostgreSQL 13 à venir prendra en charge nativement gen_random_uuid () sans avoir besoin d'activer les extensions:

PostgreSQL inclut une fonction pour générer un UUID:

gen_random_uuid ()  uuid

Cette fonction renvoie un UUID version 4 (aléatoire). Il s'agit du type d'UUID le plus utilisé et il convient à la plupart des applications.

démo db <> violon

Lukasz Szozda
la source