¿Generando un UUID en Postgres para la instrucción Insert?

368

Mi pregunta es bastante simple. Soy consciente del concepto de UUID y quiero generar uno para referirme a cada 'artículo' de una 'tienda' en mi base de datos. Parece razonable ¿verdad?

El problema es que la siguiente línea devuelve un error:

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.

He leído la página en: http://www.postgresql.org/docs/current/static/uuid-ossp.html

ingrese la descripción de la imagen aquí

Estoy ejecutando Postgres 8.4 en Ubuntu 10.04 x64.

anon58192932
fuente
8
Postgres admite de forma nativa UUID como un tipo de datos, incluso capaz de ser indexado y utilizado como clave principal. Pero para generar un valor UUID, como establecer un valor predeterminado para una columna, necesita una extensión de Postgres (un complemento). Muchas compilaciones (distribuciones) de Postgres incluyen dicha extensión pero no activan la extensión. Vea la respuesta correcta de Craig Ringer para aprender cómo activarlo.
Basil Bourque
2
Si tiene instalado uuid-ossp y aún recibe este error, intente ponerle un prefijo a la función con su nombre de esquema, por ejemploselect dbo.uuid_generate_v4()
Richard

Respuestas:

435

uuid-osspes un módulo contrib, por lo que no se carga en el servidor de forma predeterminada. Debe cargarlo en su base de datos para usarlo.

Para las versiones modernas de PostgreSQL (9.1 y posteriores) eso es fácil:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

pero para 9.0 y versiones inferiores, debe ejecutar el script SQL para cargar la extensión. Consulte la documentación de los módulos contrib en 8.4 .

Para la página 9.1 y posteriores, lea los documentos de contribución actuales y CREATE EXTENSION. Estas características no existen en las versiones 9.0 o anteriores, como su 8.4.

Si está utilizando una versión empaquetada de PostgreSQL, es posible que necesite instalar un paquete separado que contenga los módulos y las extensiones contrib. Busque en su base de datos del administrador de paquetes 'postgres' y 'contrib'.

Craig Ringer
fuente
66
@advocate Estás utilizando un PostgreSQL empaquetado en distro, por lo que deberías poder usar solo apt-get install postgresql-contribo similar. Intenta apt-cache search postgresql |grep contribencontrar el nombre del paquete que deseas.
Craig Ringer
2
sudo apt-get install postgresql-contrib se ha ejecutado con éxito. Luego tuve que ejecutar psql -d dbname -f SHAREDIR / contrib / module.sql y ahora funciona. seleccione uuid_generate_v1 (); devuelve 1 ahora ahora. ¡Muchas gracias!
anon58192932
55
Tenga en cuenta que si no instala el postgresql-contribpaquete, obtendrá el error: ERROR: no se pudo abrir el archivo de control de extensión "/usr/share/postgresql/9.3/extension/uuid-ossp.control": No existe dicho archivo o directorio
Drew Noakes
1
Publiqué ese comentario cuando la cadena de error apareció en Google. También le da un nombre de paquete específico, al menos para Ubuntu.
Drew Noakes
2
Si importó un db que ya tiene el uuid-ossp en las Extensiones, uuid_generate_v4 () podría no funcionar. Si ese es el caso, simplemente elimine la extensión, vuelva a crearla y debería funcionar.
Dragos Rusu
303

Sin extensiones (trampa)

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

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

(funciona al menos en 8.4)

  • Gracias a @Erwin Brandstetter por la clock_timestamp()explicación.

Si necesita un UUID v4 válido

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

ingrese la descripción de la imagen aquí * Gracias a @Denis Stafichuk @Karsten y @autronix


Además, en Postgres modernos, simplemente puedes lanzar:

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

ZuzEL
fuente
55
Para seguir su PS: SELECCIONEuuid_in(md5(random()::text || now()::text)::cstring);
Blaskovicz
44
@MattDiPasquale Probablemente no sea en ningún sentido "mejor" que usar uuid-ossp, pero por ejemplo estoy trabajando en una instancia de PostgreSQL donde no tengo los privilegios suficientes para instalar una extensión.
Stefan Haberl
25
@JosephLennox: clock_timestamp()es la mejor alternativa en cualquier caso para esto. A diferencia now()o CURRENT_TIMESTAMPes volátil y devuelve la hora actual real. SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring);Además, en los Postgres modernos, puedes simplemente lanzar: SELECT md5(random()::text || clock_timestamp()::text)::uuid- no necesitas más magia. Caso de uso: stackoverflow.com/a/8335376/939860
Erwin Brandstetter
17
No Si esto funciona en absoluto, es pura suerte. un UUID tiene un formato, no se trata solo de caracteres hexadecimales aleatorios, sino que el primer número del tercer grupo es la versión uuid para la integridad (generalmente 4 en estos días). Si su aplicación verifica ese dígito para ver qué versión de uuid está tratando y hace algo en consecuencia, fallará en su código.
Tuncay Göncüoğlu
77
@Tuncay Göncüoğlu: Es bastante sencillo generar un UUID v4 válido (aunque el enfoque de superposición de cadenas desperdicia 2 bits de aleatoriedad):select overlay(overlay(md5(random()::text || ':' || clock_timestamp()::text) placing '4' from 13) placing '8' from 17)::uuid;
Karsten
75

La respuesta de Craig Ringer es correcta. Aquí hay un poco más de información para Postgres 9.1 y posterior ...

¿Está disponible la extensión?

Solo puede instalar una extensión si ya se ha creado para su instalación de Postgres (su clúster en la jerga de Postgres). Por ejemplo, encontré la extensión uuid-ossp incluida como parte del instalador para Mac OS X amablemente proporcionado por EnterpriseDB.com. Cualquiera de unas pocas docenas de extensiones pueden estar disponibles.

Para ver si la extensión uuid-ossp está disponible en su clúster de Postgres, ejecute este SQL para consultar el pg_available_extensionscatálogo del sistema:

SELECT * FROM pg_available_extensions;

Instalar extensión

Para instalar esa extensión relacionada con UUID , use el comando CREATE EXTENSION como se ve en este SQL:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

Cuidado: encontré que los caracteres de MARCA DE COTIZACIÓN alrededor del nombre de la extensión son obligatorios, a pesar de la documentación que indique lo contrario.

El comité de estándares SQL o el equipo de Postgres eligieron un nombre extraño para ese comando. En mi opinión, deberían haber elegido algo como "INSTALAR EXTENSIÓN" o "USAR EXTENSIÓN".

Verificar instalación

Puede verificar que la extensión se instaló correctamente en la base de datos deseada ejecutando este SQL para consultar el pg_extensioncatálogo del sistema:

SELECT * FROM pg_extension;

UUID como valor predeterminado

Para obtener más información, consulte la pregunta: valor predeterminado para la columna UUID en Postgres

El viejo camino

La información anterior utiliza la nueva función Extensiones agregada a Postgres 9.1. En versiones anteriores, teníamos que buscar y ejecutar un script en un archivo .sql . Se agregó la función Extensiones para facilitar la instalación, intercambiando un poco más de trabajo para el creador de una extensión por menos trabajo por parte del usuario / consumidor de la extensión. Vea mi publicación de blog para más discusión.

Tipos de UUID

Por cierto, el código en la Pregunta llama a la función uuid_generate_v4(). Esto genera un tipo conocido como Versión 4 donde casi todos los 128 bits se generan aleatoriamente. Si bien esto está bien para un uso limitado en un conjunto más pequeño de filas, si desea eliminar virtualmente cualquier posibilidad de colisión, use otra "versión" de UUID.

Por ejemplo, la versión original 1 combina la dirección MAC de la computadora host con la fecha y hora actual y un número arbitrario, la posibilidad de colisiones es prácticamente nula.

Para más discusión, vea mi respuesta en la pregunta relacionada.

Albahaca Bourque
fuente
1
Y también puede usarlo CREATE EXTENSION IF NOT EXISTS ...si no está seguro y no desea verificar (en un script, por ejemplo)
Uwe Allner
2
Los UUID de la Versión 4 están bien para casi cualquier tamaño de conjunto de datos, no solo para "uso limitado en conjuntos más pequeños de filas". Tendría que generar mil millones de UUID por segundo durante aproximadamente 85 años (o alrededor de 45 millones de terabytes de datos, miles de veces más grandes que las bases de datos más grandes de la actualidad) para tener incluso un 50% de posibilidades de colisión. A menos que sea la NSA, la Versión 4 está bien para cualquier propósito. La versión 1, por otro lado, sufrió el hecho de que las direcciones MAC se asignan secuencialmente (y a menudo son falsificadas o no están disponibles), lo que es parte de por qué se introdujeron versiones posteriores.
Jazz
1
@BasilBourque El problema con v1 no es la probabilidad de colisión cuando se implementa correctamente, es la probabilidad de una implementación incorrecta. Como dice Wikipedia: "La unicidad de los UUID de las versiones 1 y 2 ... también depende de que los fabricantes de tarjetas de red asignen correctamente direcciones MAC únicas a sus tarjetas, lo que, como otros procesos de fabricación, está sujeto a error". Además, en algunos entornos en contenedores o virtualizados, las direcciones MAC verdaderas del hardware subyacente no están disponibles. Si muchos contenedores tienen el mismo MAC pero sus propios contadores clockseq, sus UUID v1 pueden colisionar.
Jazz
1
Sin embargo, las debilidades de @BasilBourque en v1 no son el punto principal de mi comentario. Su respuesta original implica que v4 no es adecuado para grandes conjuntos de datos debido a una mayor probabilidad de colisión que v1. Esto es engañoso y posiblemente falso, aunque es difícil calcular la probabilidad de colisión para v1 porque depende mucho de la implementación.
Jazz
1
@BasilBourque Por ejemplo, el proyecto nodo-uuid calcula la probabilidad de que sus contadores clockseq sean los mismos (de modo que dos procesos generarían la misma secuencia de UUID v1) que 1 en 4.6e18. Esto es muy pequeño, sí, pero es mucho más probable que la posibilidad de una colisión inmediata en v4, que es 1 en 5.3e36. Obviamente, cuanto más tiempo genere UUID v4, más probable será que se produzca una colisión, lo que no es cierto para v1, pero tendría que generar 1,52 mil millones de UUID v4 antes de que la probabilidad de colisión supere la de la implementación v1 del nodo. La mayoría de las personas no tienen 1,52 mil millones de registros por tabla.
Jazz
61

pgcrypto Extensión

A partir de Postgres 9.4, el pgcryptomódulo incluye la gen_random_uuid()función. Esta función genera uno de los tipos de UUID de versión 4 basados ​​en números aleatorios .

Obtenga módulos contrib, si aún no están disponibles.

sudo apt-get install postgresql-contrib-9.4

Usar pgcryptomódulo.

CREATE EXTENSION "pgcrypto";

La gen_random_uuid()función ahora debería estar disponible;

Ejemplo de uso.

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


Cita del documento de Postgres en eluuid-ossp módulo.

Nota: Si solo necesita UUID generados aleatoriamente (versión 4), considere usar la función gen_random_uuid () del módulo pgcrypto en su lugar.

brillante
fuente
3
Sí, pero vea también blog.starkandwayne.com/2015/05/23/… donde advierten sobre la fragmentación y sugieren uuid-ossp.
Malik A. Rumi
3
En realidad, vea postgresql.org/message-id/… donde se desacredita el problema de fragmentación de los uuidos en Postgres
Bob Kocisko
Pero postgres tiene índices agrupados en la última versión, lo que hace que la publicación enlazada en el comentario anterior no sea concluyente e incorrecta y volvemos al punto 1.
Michael Goldshteyn
1
@MichaelGoldshteyn: no, Postgres no tiene índices agrupados (a 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);

Después de leer la respuesta de @ ZuzEL, utilicé el código anterior como el valor predeterminado de la ID de la columna y funciona bien.

Paolo Fernandes
fuente
1

El próximo PostgreSQL 13 admitirá de forma nativa gen_random_uuid () sin necesidad de habilitar ninguna extensión:

PostgreSQL incluye una función para generar un UUID:

gen_random_uuid ()  uuid

Esta función devuelve un UUID versión 4 (aleatorio). Este es el tipo de UUID más utilizado y es apropiado para la mayoría de las aplicaciones.

demostración de violín db <>

Lukasz Szozda
fuente