Generujesz UUID w Postgres dla instrukcji Insert?


367

Moje pytanie jest raczej proste. Jestem świadomy koncepcji identyfikatora UUID i chcę wygenerować taki, aby odnosił się do każdego „elementu” z „sklepu” w mojej bazie danych. Wydaje się uzasadnione, prawda?

Problem polega na tym, że następujący wiersz zwraca błąd:

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.

Przeczytałem stronę: http://www.postgresql.org/docs/current/static/uuid-ossp.html

wprowadź opis zdjęcia tutaj

Używam Postgres 8.4 na Ubuntu 10.04 x64.


8
Postgres natywnie obsługuje UUID jako typ danych, a nawet może być indeksowany i używany jako klucz podstawowy. Aby jednak wygenerować wartość UUID, na przykład ustalić wartość domyślną dla kolumny, potrzebujesz rozszerzenia Postgres (wtyczki). Wiele kompilacji (dystrybucji) Postgres zawiera takie rozszerzenie, ale go nie aktywuje. Zobacz poprawną odpowiedź Craiga Ringera, aby dowiedzieć się, jak ją aktywować.
Basil Bourque,

2
Jeśli masz zainstalowany program uuid-ossp i nadal pojawia się ten błąd, spróbuj poprzedzić funkcję nazwą schematu, np.select dbo.uuid_generate_v4()
Richard

Odpowiedzi:


435

uuid-osspjest modułem contrib, więc domyślnie nie jest ładowany na serwer. Aby go użyć, musisz załadować go do swojej bazy danych.

Dla współczesnych wersji PostgreSQL (9.1 i nowszych) to łatwe:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

ale dla wersji 9.0 i niższych musisz zamiast tego uruchomić skrypt SQL, aby załadować rozszerzenie. Zobacz dokumentację modułów contrib w 8.4 .

Dla Pg 9.1 i nowszych przeczytaj aktualne dokumenty contrib i CREATE EXTENSION. Te funkcje nie istnieją w wersji 9.0 lub starszych, takich jak 8.4.

Jeśli używasz pakietowej wersji PostgreSQL, może być konieczne zainstalowanie osobnego pakietu zawierającego moduły contrib i rozszerzenia. Wyszukaj w bazie danych menedżera pakietów „postgres” i „contrib”.


6
@ advocate Używasz rozpakowanego PostgreSQL, więc powinieneś być w stanie to zrobić apt-get install postgresql-contriblub podobnie. Spróbuj apt-cache search postgresql |grep contribznaleźć żądaną nazwę pakietu.
Craig Ringer,

2
sudo apt-get install postgresql-contrib został pomyślnie uruchomiony. Następnie musiałem uruchomić psql -d nazwa_db -f SHAREDIR / contrib / module.sql i teraz działa !!! wybierz uuid_generate_v1 (); zwraca teraz 1. Dzięki wielkie!
anon58192932

5
Pamiętaj, że jeśli nie zainstalujesz postgresql-contribpakietu, pojawi się błąd: BŁĄD: nie można otworzyć pliku sterującego rozszerzeniem „/usr/share/postgresql/9.3/extension/uuid-ossp.control”: Brak takiego pliku lub katalogu
Drew Noakes

1
Opublikowałem ten komentarz, gdy ciąg błędów pojawił się w Google. Daje także określoną nazwę pakietu, przynajmniej dla Ubuntu.
Drew Noakes

2
Jeśli zaimportowano bazę danych, która ma już identyfikator UUID-OSSP w rozszerzeniach, funkcja UUID_Generate_v4 () może nie działać. W takim przypadku wystarczy usunąć rozszerzenie i utworzyć je ponownie, a powinno działać.
Dragos Rusu

302

Bez rozszerzeń (cheat)

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

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

(działa co najmniej w 8.4)

  • Podziękowania dla @Erwin Brandstetter za clock_timestamp()wyjaśnienie.

Jeśli potrzebujesz prawidłowego UUID v4

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

wprowadź opis zdjęcia tutaj * Dzięki @Denis Stafichuk @Karsten i @autronix


Ponadto we współczesnym Postgres możesz po prostu rzucić:

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


5
Aby śledzić swoje PS: SELECTuuid_in(md5(random()::text || now()::text)::cstring);
Blaskovicz

4
@MattDiPasquale Prawdopodobnie nie jest w żadnym sensie „lepszy” niż używanie uuid-ossp, ale pracuję na przykład nad instancją PostgreSQL, w której nie mam wystarczających uprawnień, aby zainstalować rozszerzenie.
Stefan Haberl,

25
@JosephLennox: clock_timestamp()jest lepszą alternatywą w obu przypadkach. W przeciwieństwie do now()lub CURRENT_TIMESTAMPjest niestabilny i zwraca aktualny aktualny czas. SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring);Ponadto we współczesnym Postgresie możesz po prostu rzucić: SELECT md5(random()::text || clock_timestamp()::text)::uuid- nie potrzebujesz więcej magii. Przypadek użycia: stackoverflow.com/a/8335376/939860
Erwin Brandstetter

17
Nie. Jeśli to w ogóle zadziała, wystarczy. identyfikator UUID ma format, a nie tylko losowe znaki szesnastkowe zrzucane razem. Pierwsza liczba trzeciej grupy to wersja UUID dla intencji (zwykle 4 obecnie). Jeśli aplikacja sprawdzi tę cyfrę, aby zobaczyć, z którą wersją uuid sobie radzi, i odpowiednio coś zrobi, kod nie powiedzie się.
Tuncay Göncüoğlu

7
@Tuncay Göncüoğlu: Generowanie prawidłowego UUID v4 jest dość proste (metoda nakładania łańcuchów marnuje 2 bity losowości):select overlay(overlay(md5(random()::text || ':' || clock_timestamp()::text) placing '4' from 13) placing '8' from 17)::uuid;
Karsten

75

Odpowiedź Craig Ringer jest poprawna. Oto trochę więcej informacji na temat Postgres 9.1 i nowszych…

Czy dostępne jest rozszerzenie?

Rozszerzenie można zainstalować tylko wtedy, gdy zostało ono już zbudowane do instalacji Postgres ( klaster w języku Lingo Postgres). Na przykład znalazłem rozszerzenie uuid-ossp zawarte w ramach instalatora dla systemu Mac OS X udostępnionego przez EnterpriseDB.com. Dostępne może być dowolne z kilkudziesięciu rozszerzeń .

Aby sprawdzić, czy rozszerzenie uuid-ossp jest dostępne w klastrze Postgres, uruchom ten kod SQL, aby wysłać zapytanie do pg_available_extensionskatalogu systemowego:

SELECT * FROM pg_available_extensions;

Zainstaluj rozszerzenie

Aby zainstalować to rozszerzenie związane z UUID , użyj polecenia CREATE EXTENSION, jak widać w tym SQL:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

Uwaga: Znalazłem wymagane znaki ZNAK QUOTATION wokół nazwy rozszerzenia, mimo że dokumentacja jest wręcz przeciwna.

Komitet ds. Standardów SQL lub zespół Postgres wybrał dla tego polecenia nieparzystą nazwę. Moim zdaniem powinni wybrać coś takiego jak „ZAINSTALUJ PRZEDŁUŻENIE” lub „UŻYJ PRZEDŁUŻENIA”.

Sprawdź instalację

Możesz sprawdzić, czy rozszerzenie zostało pomyślnie zainstalowane w wybranej bazie danych, uruchamiając ten kod SQL w celu przeszukania pg_extensionkatalogu systemowego:

SELECT * FROM pg_extension;

UUID jako wartość domyślna

Aby uzyskać więcej informacji, zobacz pytanie: Wartość domyślna dla kolumny UUID w Postgres

The Old Way

Powyższe informacje wykorzystują nową funkcję Rozszerzeń dodaną do Postgres 9.1. W poprzednich wersjach musieliśmy znaleźć i uruchomić skrypt w pliku .sql . Dodano funkcję Rozszerzenia, aby ułatwić instalację, zamieniając nieco więcej pracy dla twórcy rozszerzenia na mniej pracy ze strony użytkownika / konsumenta rozszerzenia. Zobacz mój post na blogu, aby uzyskać więcej dyskusji.

Rodzaje UUID

Nawiasem mówiąc, kod w pytaniu wywołuje funkcję uuid_generate_v4(). Generuje to typ znany jako Wersja 4, w której prawie wszystkie 128 bitów jest generowanych losowo. Chociaż jest to odpowiednie w przypadku ograniczonego użycia w mniejszym zestawie wierszy, jeśli chcesz praktycznie wyeliminować jakąkolwiek możliwość kolizji, użyj innej „wersji” UUID.

Na przykład oryginalna wersja 1 łączy adres MAC komputera-hosta z bieżącą datą i godziną i dowolną liczbą, prawdopodobieństwo kolizji jest praktycznie zerowe.

Aby uzyskać więcej dyskusji, zobacz moją odpowiedź na powiązane pytanie.


1
Możesz także użyć, CREATE EXTENSION IF NOT EXISTS ...jeśli nie jesteś pewien i nie chcesz sprawdzić (np. W skrypcie)
Uwe Allner

2
Identyfikatory UUID w wersji 4 są odpowiednie dla prawie każdego zestawu danych wielkości, nie tylko „ograniczonego użycia w mniejszych zestawach wierszy”. Będziesz musiał wygenerować 1 miliard UUID na sekundę przez około 85 lat (lub około 45 milionów terabajtów danych, tysiące razy większych niż obecnie największe bazy danych), aby mieć nawet 50% szansy na kolizję. Jeśli nie jesteś NSA, wersja 4 jest odpowiednia do dowolnego celu. Z drugiej strony wersja 1 cierpiała z powodu tego, że adresy MAC są sekwencyjnie przypisywane (i często sfałszowane lub niedostępne), co jest jednym z powodów, dla których wprowadzono późniejsze wersje.
Jazz

1
@BasilBourque Problem z wersją v1 nie polega na prawdopodobieństwie kolizji, jeśli jest poprawnie zaimplementowana, jest to prawdopodobieństwo nieprawidłowej implementacji. Jak to ujęła Wikipedia: „Unikalność UUID wersji 1 i 2… zależy również od tego, czy producenci kart sieciowych prawidłowo przypisują swoim kartom unikalne adresy MAC, które podobnie jak inne procesy produkcyjne są obarczone błędem”. Ponadto w niektórych środowiskach konteneryzowanych lub zwirtualizowanych prawdziwe adresy MAC z podstawowego sprzętu nie są dostępne. Jeśli wiele kontenerów ma ten sam adres MAC, ale własne liczniki zegara, ich identyfikatory UUID v1 mogą się kolidować.
Jazz

1
@BasilBourque Słabości w v1 nie są jednak głównym punktem mojego komentarza. Oryginalna odpowiedź sugeruje, że wersja 4 nie jest odpowiednia dla dużych zestawów danych ze względu na większe prawdopodobieństwo kolizji niż wersja 1. Jest to mylące i być może fałszywe, choć trudno jest obliczyć prawdopodobieństwo kolizji dla wersji 1, ponieważ jest ona tak bardzo zależna od implementacji.
Jazz

1
@BasilBourque Na przykład projekt UUID węzła oblicza prawdopodobieństwo, że ich liczniki sekwensów zegarowych będą takie same (tak, że dwa procesy wygenerują tę samą sekwencję UUID v1) jak 1 w 4.6e18. Jest to niewielkie, tak, ale znacznie bardziej prawdopodobne niż prawdopodobieństwo natychmiastowej kolizji w wersji 4, która wynosi 1 w 5.3e36. Oczywiście im dłużej generujesz UUID v4, tym bardziej prawdopodobne jest kolizja, co nie jest prawdą w przypadku v1, ale musisz wygenerować 1,52 miliarda UUID v4, zanim prawdopodobieństwo kolizji przekroczy prawdopodobieństwo implementacji v1 węzła. Większość ludzi nie ma 1,52 miliarda rekordów na tabelę.
Jazz

61

pgcrypto Rozbudowa

Począwszy od Postgres 9.4, pgcryptomoduł zawiera gen_random_uuid()funkcję. Ta funkcja generuje jeden z UUID typu 4 w oparciu o liczby losowe .

Zdobądź moduły contrib, jeśli jeszcze nie są dostępne.

sudo apt-get install postgresql-contrib-9.4

Użyj pgcryptomodułu.

CREATE EXTENSION "pgcrypto";

gen_random_uuid()Funkcja powinna teraz dostępne;

Przykładowe użycie.

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


Cytat z dokumentu Postgres wuuid-ossp module.

Uwaga: Jeśli potrzebujesz tylko UUID generowanych losowo (wersja 4), rozważ użycie funkcji gen_random_uuid () z modułu pgcrypto.


3
Tak, ale zobacz także blog.starkandwayne.com/2015/05/23/…, gdzie ostrzegają przed fragmentacją i sugerują zamiast tego uuid-ossp.
Malik A. Rumi

3
W rzeczywistości patrz postgresql.org/message-id/…, gdzie problem fragmentacji UUID w Postgres jest podważany
Bob Kocisko

Ale postgres ma indeksy klastrowe w najnowszej wersji, co sprawia, że ​​post link w powyższym komentarzu jest niejednoznaczny i niepoprawny, a my wracamy do kwadratu 1.
Michael Goldshteyn

1
@MichaelGoldshteyn: nie, Postgres nie ma indeksów klastrowych (od Postgres 12)
a_horse_w_nazwie

3
ALTER TABLE table_name ALTER COLUMN id SET DEFAULT uuid_in((md5((random())::text))::cstring);

Po przeczytaniu odpowiedzi @ ZuzEL użyłem powyższego kodu jako domyślnej wartości identyfikatora kolumny i działa dobrze.


1

Nadchodząca PostgreSQL 13 będzie obsługiwać natywnie gen_random_uuid () bez potrzeby włączania jakichkolwiek rozszerzeń:

PostgreSQL zawiera jedną funkcję do generowania UUID:

gen_random_uuid ()  uuid

Ta funkcja zwraca UUID wersji 4 (losowy). Jest to najczęściej używany typ UUID i jest odpowiedni dla większości aplikacji.

db <> demo skrzypiec

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.