Gerando um UUID no Postgres para a instrução Insert?

368

Minha pergunta é bastante simples. Estou ciente do conceito de um UUID e quero gerar um para se referir a cada 'item' de uma 'loja' no meu banco de dados com. Parece razoável, certo?

O problema é que a seguinte linha retorna um erro:

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.

Eu li a página em: http://www.postgresql.org/docs/current/static/uuid-ossp.html

insira a descrição da imagem aqui

Estou executando o Postgres 8.4 no Ubuntu 10.04 x64.

anon58192932
fonte
8
O Postgres suporta nativamente o UUID como um tipo de dados, mesmo capaz de ser indexado e usado como chave primária. Mas para gerar um valor UUID, como estabelecer um valor padrão para uma coluna, você precisa de uma extensão do Postgres (um plugin). Muitas construções (distribuições) do Postgres incluem essa extensão, mas não a ativam. Veja a resposta correta de Craig Ringer para saber como ativá-la.
Basil Bourque
2
Se você possui o uuid-ossp instalado e ainda assim obtém esse erro, tente prefixar a função com o nome do seu esquema, por exemplo:select dbo.uuid_generate_v4()
Richard

Respostas:

435

uuid-osspé um módulo contrib, portanto, não é carregado no servidor por padrão. Você deve carregá-lo no seu banco de dados para usá-lo.

Para versões modernas do PostgreSQL (9.1 e mais recente), é fácil:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

mas para 9.0 e abaixo, você deve executar o script SQL para carregar a extensão. Veja a documentação dos módulos contrib na 8.4 .

Para a página 9.1 e mais recente, leia os documentos de contribuição atuais e CREATE EXTENSION. Esses recursos não existem nas versões 9.0 ou anteriores, como a 8.4.

Se você estiver usando uma versão empacotada do PostgreSQL, poderá ser necessário instalar um pacote separado contendo os módulos e extensões do contrib. Pesquise no banco de dados do gerenciador de pacotes por 'postgres' e 'contrib'.

Craig Ringer
fonte
6
@advocate Você está usando um PostgreSQL empacotado em distribuição, para poder usar apenas apt-get install postgresql-contribou algo semelhante. Tente apt-cache search postgresql |grep contribencontrar o nome do pacote que você deseja.
Craig Ringer
2
sudo apt-get install O postgresql-contrib foi executado com sucesso. Então eu tive que executar o psql -d nome_bd -f SHAREDIR / contrib / module.sql e agora funciona !!! selecione uuid_generate_v1 (); retorna 1 agora agora. Muito obrigado!
precisa saber é o seguinte
5
Observe que, se você não instalar o postgresql-contribpacote, receberá o erro: ERRO: não foi possível abrir o arquivo de controle de extensão "/usr/share/postgresql/9.3/extension/uuid-ossp.control": esse arquivo ou diretório não existe
de Drew Noakes
11
Publiquei esse comentário quando a sequência de erros apareceu no Google. Também fornece um nome de pacote específico, pelo menos para o Ubuntu.
Drew Noakes
2
Se você importou um banco de dados que já possui o uuid-ossp nas Extensões, uuid_generate_v4 () pode não funcionar. Se for esse o caso, remova a extensão e crie-a novamente e ela deve funcionar.
Dragos Rusu
302

Sem extensões (fraude)

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

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

(funciona pelo menos em 8.4)

  • Obrigado a @Erwin Brandstetter pela clock_timestamp()explicação.

Se você precisar de um 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);

insira a descrição da imagem aqui * Agradecimentos a @Denis Stafichuk @Karsten e @autronix


Além disso, no Postgres moderno, você pode simplesmente transmitir:

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

ZuzEL
fonte
5
Para acompanhar seu PS: SELECTuuid_in(md5(random()::text || now()::text)::cstring);
Blaskovicz
4
@MattDiPasquale Provavelmente não em nenhum sentido "melhor" do que usar uuid-ossp, mas estou trabalhando, por exemplo, em uma instância do PostgreSQL em que não tenho privilégios suficientes para instalar uma extensão.
Stefan Haberl
25
@ JosephphLennox: clock_timestamp()é a melhor alternativa em ambos os casos para isso. Diferente now()ou CURRENT_TIMESTAMPé volátil e retorna a hora atual real. SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring);Além disso, no Postgres moderno, você pode simplesmente lançar: SELECT md5(random()::text || clock_timestamp()::text)::uuid- não há necessidade de mais mágica. Caso de uso: stackoverflow.com/a/8335376/939860
Erwin Brandstetter
17
Não. Se isso funcionar com toda a sua pura sorte. um UUID tem um formato, não apenas caracteres hexadecimais aleatórios lançados juntos. O primeiro número do terceiro grupo é a versão uuid por intenção (geralmente 4 atualmente). Se o seu aplicativo verificar esse dígito para ver com qual versão do uuid está lidando e fazer alguma coisa de acordo, ele falhará no seu código.
Tuncay Göncüoğlu
7
@Tuncay Göncüoğlu: É bastante simples gerar um UUID v4 válido (a abordagem de sobreposição de cadeias desperdiça 2 bits de aleatoriedade):select overlay(overlay(md5(random()::text || ':' || clock_timestamp()::text) placing '4' from 13) placing '8' from 17)::uuid;
Karsten
75

A resposta de Craig Ringer está correta. Aqui está um pouco mais de informação para o Postgres 9.1 e posterior ...

A extensão está disponível?

Você só pode instalar uma extensão se ela já tiver sido criada para a instalação do Postgres (seu cluster no jargão do Postgres). Por exemplo, eu achei a extensão uuid-ossp incluída como parte do instalador do Mac OS X, gentilmente fornecido pelo EnterpriseDB.com. Qualquer uma das dezenas de extensões pode estar disponível.

Para verificar se a extensão uuid-ossp está disponível no cluster do Postgres, execute este SQL para consultar o pg_available_extensionscatálogo do sistema:

SELECT * FROM pg_available_extensions;

Instalar extensão

Para instalar essa extensão relacionada ao UUID , use o comando CREATE EXTENSION conforme visto neste SQL:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

Cuidado: achei que os caracteres de MARCAÇÃO DE COTAÇÃO em torno do nome da extensão eram necessários, apesar da documentação em contrário.

O comitê de padrões SQL ou a equipe do Postgres escolheu um nome estranho para esse comando. Na minha opinião, eles deveriam ter escolhido algo como "INSTALAR EXTENSÃO" ou "USAR EXTENSÃO".

Verificar instalação

Você pode verificar se a extensão foi instalada com sucesso no banco de dados desejado executando este SQL para consultar o pg_extensioncatálogo do sistema:

SELECT * FROM pg_extension;

UUID como valor padrão

Para obter mais informações, consulte a pergunta: Valor padrão para a coluna UUID no Postgres

O Caminho Antigo

As informações acima usam o novo recurso Extensões adicionado ao Postgres 9.1. Nas versões anteriores, tivemos que encontrar e executar um script em um arquivo .sql . O recurso Extensões foi adicionado para facilitar a instalação, negociando um pouco mais de trabalho pelo criador de uma extensão por menos trabalho por parte do usuário / consumidor da extensão. Veja minha postagem no blog para mais discussões.

Tipos de UUIDs

By the way, o código em questão chama a função uuid_generate_v4(). Isso gera um tipo conhecido como versão 4 onde quase todos os 128 bits são gerados aleatoriamente. Embora isso seja adequado para uso limitado em um conjunto menor de linhas, se você quiser praticamente eliminar qualquer possibilidade de colisão, use outra "versão" do UUID.

Por exemplo, a versão 1 original combina o endereço MAC do computador host com a data e hora atuais e um número arbitrário, a chance de colisões é praticamente nula.

Para mais discussão, consulte minha resposta sobre a questão relacionada.

Basil Bourque
fonte
11
E você também pode usar CREATE EXTENSION IF NOT EXISTS ...se você não tem certeza e não quiser verificar (em um script por exemplo)
Uwe Allner
2
Os UUIDs da versão 4 são adequados para praticamente qualquer tamanho de conjunto de dados, não apenas para "uso limitado em conjuntos menores de linhas". Você precisaria gerar 1 bilhão de UUIDs por segundo por cerca de 85 anos (ou cerca de 45 milhões de terabytes de dados, milhares de vezes maiores que os maiores bancos de dados de hoje) para ter 50% de chance de colisão. A menos que você seja da NSA, a Versão 4 é adequada para qualquer finalidade. A versão 1, por outro lado, sofria com o fato de os endereços MAC serem atribuídos seqüencialmente (e geralmente serem falsificados ou indisponíveis), o que é parte do motivo pelo qual versões posteriores foram introduzidas.
Jazz
11
@BasilBourque O problema com a v1 não é a probabilidade de colisão quando implementada corretamente, é a probabilidade de implementação incorreta. Como a Wikipedia diz: "A exclusividade das UUIDs das versões 1 e 2 ... também depende de os fabricantes de placas de rede atribuírem corretamente endereços MAC exclusivos às suas placas, o que, como outros processos de fabricação, está sujeito a erros". Além disso, em alguns ambientes em contêineres ou virtualizados, os endereços MAC verdadeiros do hardware subjacente não estão disponíveis. Se muitos contêineres tiverem o mesmo MAC, mas seus próprios contadores de clockseq, seus UUIDs v1 poderão colidir.
Jazz
11
@BasilBourque As fraquezas da v1 não são o ponto principal do meu comentário, no entanto. Sua resposta original implica que a v4 não é adequada para grandes conjuntos de dados devido a uma maior probabilidade de colisão que a v1. Isso é enganoso e possivelmente falso, embora seja difícil calcular a probabilidade de colisão para a v1 porque é muito dependente da implementação.
Jazz
11
@BasilBourque Por exemplo, o projeto node-uuid calcula a probabilidade de seus contadores de clockseq serem os mesmos (para que dois processos gerem a mesma sequência de UUIDs v1) como 1 em 4.6e18. Isso é minúsculo, sim, mas muito mais provável que a chance de colisão imediata na v4, que é 1 em 5.3e36. Obviamente, quanto mais tempo você gerar UUIDs v4, maior será a probabilidade de uma colisão, o que não é verdade para a v1, mas você precisará gerar 1,52 bilhão de UUIDs v4 antes que a probabilidade de colisão exceda a da implementação da v1 do nó. A maioria das pessoas não possui 1,52 bilhão de registros por tabela.
Jazz
61

pgcrypto Extensão

A partir do Postgres 9.4, o pgcryptomódulo inclui a gen_random_uuid()função Essa função gera um tipo de UUID versão 4 baseado em número aleatório .

Obtenha módulos contrib, se ainda não estiverem disponíveis.

sudo apt-get install postgresql-contrib-9.4

Use o pgcryptomódulo.

CREATE EXTENSION "pgcrypto";

A gen_random_uuid()função agora deve estar disponível;

Exemplo de uso.

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


Citação do documento Postgres nouuid-ossp módulo.

Nota: Se você precisar apenas de UUIDs gerados aleatoriamente (versão 4), considere usar a função gen_random_uuid () do módulo pgcrypto.

brillout
fonte
3
Sim, mas veja também blog.starkandwayne.com/2015/05/23/… onde eles alertam sobre fragmentação e sugerem uuid-ossp.
Malik A. Rumi
3
Na verdade, consulte postgresql.org/message-id/… onde o problema de fragmentação de uuid no Postgres é desmascarado
Bob Kocisko
Mas postgres não ter agrupado índices na versão mais recente, tornando o pós ligados no comentário acima inconclusivos e incorreta e estamos de volta à estaca 1.
Michael Goldshteyn
11
@MichaelGoldshteyn: não, o Postgres não possui índices agrupados (a partir do Postgres 12)
a_horse_with_no_name
3
ALTER TABLE table_name ALTER COLUMN id SET DEFAULT uuid_in((md5((random())::text))::cstring);

Depois de ler a resposta do @ ZuzEL, usei o código acima como o valor padrão do ID da coluna e ele está funcionando bem.

Paolo Fernandes
fonte
1

O próximo PostgreSQL 13 suportará nativamente gen_random_uuid () sem a necessidade de ativar nenhuma extensão:

O PostgreSQL inclui uma função para gerar um UUID:

gen_random_uuid ()  uuid

Esta função retorna um UUID da versão 4 (aleatória). Esse é o tipo de UUID mais usado e é apropriado para a maioria dos aplicativos.

db <> demo de violino

Lukasz Szozda
fonte