Membuat UUID di Postgres untuk pernyataan Insert?

368

Pertanyaan saya agak sederhana. Saya mengetahui konsep UUID dan saya ingin membuat satu untuk merujuk ke setiap 'item' dari 'toko' di DB saya. Tampaknya masuk akal bukan?

Masalahnya adalah baris berikut mengembalikan kesalahan:

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.

Saya telah membaca halaman di: http://www.postgresql.org/docs/current/static/uuid-ossp.html

masukkan deskripsi gambar di sini

Saya menjalankan Postgres 8.4 di Ubuntu 10.04 x64.

anon58192932
sumber
8
Postgres secara alami mendukung UUID sebagai tipe data, bahkan mampu diindeks dan digunakan sebagai kunci utama. Tetapi untuk menghasilkan nilai UUID, seperti untuk menetapkan nilai default untuk sebuah kolom, Anda memerlukan ekstensi Postgres (sebuah plugin). Banyak build (distribusi) Postgres menyertakan ekstensi seperti itu tetapi tidak mengaktifkan ekstensi. Lihat jawaban yang benar oleh Craig Ringer untuk mempelajari cara mengaktifkannya.
Basil Bourque
2
Jika Anda telah menginstal uuid-ossp & Anda masih mendapatkan kesalahan ini, coba awali fungsi dengan nama skema Anda, misalnyaselect dbo.uuid_generate_v4()
Richard

Jawaban:

435

uuid-osspadalah modul contrib, jadi modul ini tidak dimuat ke server secara default. Anda harus memuatnya ke dalam basis data Anda untuk menggunakannya.

Untuk versi PostgreSQL modern (9.1 dan yang lebih baru) itu mudah:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

tetapi untuk 9.0 dan di bawah Anda harus menjalankan skrip SQL untuk memuat ekstensi. Lihat dokumentasi untuk modul contrib di 8.4 .

Untuk Hal 9.1 dan yang lebih baru, bacalah dokumen contrib saat ini dan CREATE EXTENSION. Fitur-fitur ini tidak ada dalam versi 9.0 atau yang lebih lama, seperti 8.4 Anda.

Jika Anda menggunakan PostgreSQL versi paket, Anda mungkin perlu menginstal paket terpisah yang berisi modul dan ekstensi contrib. Cari basis data manajer paket Anda untuk 'postgres' dan 'contrib'.

Craig Ringer
sumber
6
@advocate Anda menggunakan PostgreSQL yang distro-packaged sehingga Anda harus bisa dengan cara yang sama apt-get install postgresql-contribatau serupa. Cobalah apt-cache search postgresql |grep contribuntuk menemukan nama paket yang Anda inginkan.
Craig Ringer
2
sudo apt-get install postgresql-contrib telah berhasil dijalankan. Kemudian saya harus menjalankan psql -d dbname -f SHAREDIR / contrib / module.sql dan sekarang ia berfungsi !!! pilih uuid_generate_v1 (); mengembalikan 1 sekarang sekarang. Terima kasih banyak!
anon58192932
5
Perhatikan bahwa jika Anda tidak menginstal postgresql-contribpaket, Anda akan mendapatkan kesalahan: ERROR: tidak dapat membuka file kontrol ekstensi "/usr/share/postgresql/9.3/extension/uuid-ossp.control": Tidak ada file atau direktori tersebut
Drew Noakes
1
Saya memposting komentar itu ketika string kesalahan muncul di Google. Juga memberikan nama paket spesifik, setidaknya untuk Ubuntu.
Drew Noakes
2
Jika Anda mengimpor db yang sudah memiliki uuid-ossp di Extensions, uuid_generate_v4 () mungkin tidak berfungsi. Jika itu masalahnya, hapus saja ekstensi, dan buat lagi dan itu akan berfungsi.
Dragos Rusu
303

Tanpa ekstensi (cheat)

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

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

(bekerja setidaknya dalam 8.4)

  • Terima kasih kepada @Erwin Brandstetter untuk clock_timestamp()penjelasannya.

Jika Anda memerlukan UUID v4 yang valid

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

masukkan deskripsi gambar di sini * Terima kasih kepada @Denis Stafichuk @ Karsten dan @autronix


Juga, di Postgres modern, Anda dapat dengan mudah memberikan:

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

ZuzEL
sumber
5
Untuk menindaklanjuti PS Anda: SELECTuuid_in(md5(random()::text || now()::text)::cstring);
Blaskovicz
4
@MattDiPasquale Mungkin tidak dalam arti "lebih baik" daripada menggunakan uuid-ossp, tapi saya misalnya bekerja pada contoh PostgreSQL di mana saya tidak memiliki hak yang cukup untuk menginstal ekstensi.
Stefan Haberl
25
@ JosephLennox: clock_timestamp()adalah alternatif yang lebih baik dalam hal ini. Berbeda now()atau CURRENT_TIMESTAMPtidak stabil dan mengembalikan waktu aktual saat ini. SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring);Selain itu, di Postgres modern, Anda dapat menggunakan: SELECT md5(random()::text || clock_timestamp()::text)::uuid- tidak perlu sihir lagi. Use-case: stackoverflow.com/a/8335376/939860
Erwin Brandstetter
17
Nggak. Jika ini bekerja sama sekali keberuntungannya semata. UUID memiliki format, bukan hanya karakter hex acak yang disatukan. Angka pertama dari grup ke-3 adalah versi uuid untuk tujuan (biasanya 4 hari ini). Jika aplikasi Anda memeriksa angka itu untuk melihat versi apa yang digunakannya, dan melakukan sesuatu yang sesuai, itu akan gagal dalam kode Anda.
Tuncay Göncüoğlu
7
@Tuncay Göncüoğlu: Ini cukup mudah untuk menghasilkan UUID v4 yang valid (pendekatan overlay string membuang 2 bit keacakan):select overlay(overlay(md5(random()::text || ':' || clock_timestamp()::text) placing '4' from 13) placing '8' from 17)::uuid;
Karsten
75

The jawaban dengan Craig Ringer benar. Berikut sedikit info untuk Postgres 9.1 dan yang lebih baru ...

Apakah Ekstensi Tersedia?

Anda hanya dapat menginstal ekstensi jika sudah dibangun untuk instalasi Postgres Anda ( cluster Anda dalam istilah Postgres). Sebagai contoh, saya menemukan ekstensi uuid-ossp disertakan sebagai bagian dari penginstal untuk Mac OS X yang disediakan oleh EnterpriseDB.com. Salah satu dari beberapa lusin ekstensi mungkin tersedia.

Untuk melihat apakah ekstensi uuid-ossp tersedia di cluster Postgres Anda, jalankan SQL ini untuk meminta pg_available_extensionskatalog sistem:

SELECT * FROM pg_available_extensions;

Pasang Ekstensi

Untuk menginstal ekstensi terkait UUID itu , gunakan perintah CREATE EXTENSION seperti yang terlihat dalam SQL ini:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

Hati-hati: Saya menemukan karakter MARK KUTIPAN di sekitar nama ekstensi diperlukan, meskipun dokumentasi sebaliknya.

Komite standar SQL atau tim Postgres memilih nama aneh untuk perintah itu. Menurut saya, mereka seharusnya memilih sesuatu seperti "INSTALL EXTENSION" atau "USE EXTENSION".

Verifikasi Instalasi

Anda dapat memverifikasi ekstensi berhasil diinstal dalam database yang diinginkan dengan menjalankan SQL ini untuk meminta pg_extensionkatalog sistem:

SELECT * FROM pg_extension;

UUID sebagai nilai default

Untuk info lebih lanjut, lihat Pertanyaan: Nilai default untuk kolom UUID di Postgres

Jalan Lama

Informasi di atas menggunakan fitur Extensions baru yang ditambahkan ke Postgres 9.1. Di versi sebelumnya, kami harus menemukan dan menjalankan skrip dalam file .sql . Fitur Extensions ditambahkan untuk membuat instalasi lebih mudah, memperdagangkan sedikit lebih banyak pekerjaan untuk pencipta ekstensi untuk lebih sedikit pekerjaan pada bagian pengguna / konsumen ekstensi. Lihat posting blog saya untuk diskusi lebih lanjut.

Jenis UUID

Ngomong-ngomong, kode dalam Pertanyaan memanggil fungsi uuid_generate_v4(). Ini menghasilkan jenis yang dikenal sebagai Versi 4 di mana hampir semua 128 bit dihasilkan secara acak. Meskipun ini diperbolehkan untuk penggunaan terbatas pada set baris yang lebih kecil, jika Anda ingin menghilangkan kemungkinan tabrakan, gunakan "versi" UUID lainnya.

Sebagai contoh, Versi 1 asli menggabungkan alamat MAC dari komputer host dengan tanggal-waktu saat ini dan nomor yang berubah-ubah, kemungkinan tabrakan praktis nol.

Untuk diskusi lebih lanjut, lihat Jawaban saya pada Pertanyaan terkait.

Basil Bourque
sumber
1
Dan Anda juga dapat menggunakan CREATE EXTENSION IF NOT EXISTS ...jika Anda tidak yakin dan tidak ingin memeriksa (dalam skrip misalnya)
Uwe Allner
2
Versi 4 UUID baik untuk hampir semua kumpulan data ukuran, tidak hanya "penggunaan terbatas pada set baris yang lebih kecil." Anda harus menghasilkan 1 miliar UUID per detik selama sekitar 85 tahun (atau sekitar 45 juta terabyte data, ribuan kali lebih besar dari basis data terbesar saat ini) bahkan untuk memiliki peluang tabrakan 50%. Kecuali jika Anda adalah NSA, Versi 4 tidak masalah untuk tujuan apa pun. Versi 1, di sisi lain, menderita dari kenyataan bahwa alamat MAC ditugaskan secara berurutan (dan sering dipalsukan atau tidak tersedia), yang merupakan bagian dari mengapa versi selanjutnya diperkenalkan.
Jazz
1
@ BasilBourque Masalah dengan v1 bukanlah probabilitas tabrakan ketika diimplementasikan dengan benar, ini adalah kemungkinan implementasi yang salah. Seperti yang dikatakan Wikipedia: "Keunikan UUID versi 1 dan 2 ... juga tergantung pada produsen kartu jaringan yang secara tepat memberikan alamat MAC unik ke kartu mereka, yang seperti proses pembuatan lainnya dapat mengalami kesalahan." Selain itu, di beberapa lingkungan kemas atau virtual, alamat MAC yang sebenarnya dari perangkat keras yang mendasarinya tidak tersedia. Jika banyak kontainer memiliki MAC yang sama tetapi counter clockseq mereka sendiri, UUID v1 mereka mungkin bertabrakan.
Jazz
1
@BasilBourque Kelemahan pada v1 bukan poin utama dari komentar saya. Jawaban awal Anda menyiratkan bahwa v4 tidak cocok untuk kumpulan data besar karena probabilitas tabrakan yang lebih tinggi daripada v1. Ini menyesatkan dan mungkin salah, meskipun sulit untuk menghitung probabilitas tabrakan untuk v1 karena sangat tergantung pada implementasi.
Jazz
1
@ BasilBourque Sebagai contoh, proyek node-uuid menghitung probabilitas penghitung clockseq mereka sama (sehingga dua proses akan menghasilkan urutan UUID v1 yang sama) seperti 1 dalam 4.6e18. Ini kecil, ya, tetapi jauh lebih mungkin daripada kemungkinan tabrakan langsung di v4, yaitu 1 dalam 5.3e36. Jelas semakin lama Anda menghasilkan v4 UUID, semakin besar kemungkinan tabrakan, yang tidak berlaku untuk v1, tetapi Anda harus menghasilkan 1,52 miliar v4 UUID sebelum kemungkinan tabrakan melebihi implementasi v1 node. Kebanyakan orang tidak memiliki 1,52 miliar rekaman per tabel.
Jazz
61

pgcrypto Perpanjangan

Pada Postgres 9.4, pgcryptomodul menyertakan gen_random_uuid()fungsi. Fungsi ini menghasilkan salah satu jenis UUID versi 4 berbasis nomor acak .

Dapatkan modul contrib, jika belum tersedia.

sudo apt-get install postgresql-contrib-9.4

Gunakan pgcryptomodul.

CREATE EXTENSION "pgcrypto";

The gen_random_uuid()Fungsi sekarang harus tersedia;

Contoh penggunaan.

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


Kutipan dari Postgres doc onuuid-ossp module.

Catatan: Jika Anda hanya membutuhkan UUID yang dibuat secara acak (versi 4), pertimbangkan untuk menggunakan fungsi gen_random_uuid () dari modul pgcrypto.

brillout
sumber
3
Ya, tetapi lihat juga blog.starkandwayne.com/2015/05/05/23 di mana mereka memperingatkan tentang fragmentasi dan menyarankan uuid-ossp sebagai gantinya.
Malik A. Rumi
3
Sebenarnya, lihat postgresql.org/message-id/… di mana masalah fragmentasi uuid di Postgres dibantah
Bob Kocisko
Tetapi postgres memang memiliki pengelompokan indeks dalam versi terbaru, membuat pos yang tertaut dalam komentar di atas tidak meyakinkan dan salah dan kami segera kembali ke titik 1.
Michael Goldshteyn
1
@MichaelGoldshteyn: tidak, Postgres tidak memiliki indeks yang dikelompokkan (per Postgres 12)
a_horse_with_no_name
3
ALTER TABLE table_name ALTER COLUMN id SET DEFAULT uuid_in((md5((random())::text))::cstring);

Setelah membaca jawaban @ ZuzEL, saya menggunakan kode di atas sebagai nilai default id kolom dan berfungsi dengan baik.

Paolo Fernandes
sumber
1

PostgreSQL 13 yang akan datang akan mendukung native gen_random_uuid () tanpa perlu mengaktifkan ekstensi apa pun:

PostgreSQL mencakup satu fungsi untuk menghasilkan UUID:

gen_random_uuid ()  uuid

Fungsi ini mengembalikan UUID versi 4 (acak). Ini adalah jenis UUID yang paling umum digunakan dan sesuai untuk sebagian besar aplikasi.

db <> demo biola

Lukasz Szozda
sumber