Генерация UUID в Postgres для оператора вставки?

368

Мой вопрос довольно прост. Мне известна концепция UUID, и я хочу сгенерировать ее для ссылки на каждый «элемент» из «хранилища» в моей БД. Кажется разумным, верно?

Проблема в следующей строке возвращает ошибку:

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.

Я прочитал страницу по адресу: http://www.postgresql.org/docs/current/static/uuid-ossp.html

введите описание изображения здесь

Я использую Postgres 8.4 на Ubuntu 10.04 x64.

anon58192932
источник
8
Postgres изначально поддерживает UUID как тип данных, даже может быть проиндексирован и использован в качестве первичного ключа. Но для создания значения UUID, например, для установки значения по умолчанию для столбца, вам нужно расширение Postgres (плагин). Многие сборки (дистрибутивы) Postgres включают такое расширение, но не активируют расширение. Посмотрите правильный ответ Крейга Рингера, чтобы узнать, как его активировать.
Василий Бурк
2
Если вы установили UUID-OSSP и вы все равно получите эту попытку ошибки Приставки функции с именем схемы, напримерselect dbo.uuid_generate_v4()
Richard

Ответы:

435

uuid-osspэто модуль contrib, поэтому по умолчанию он не загружается на сервер. Вы должны загрузить его в свою базу данных, чтобы использовать его.

Для современных версий PostgreSQL (9.1 и новее) это просто:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

но для 9.0 и ниже вы должны вместо этого запустить скрипт SQL для загрузки расширения. См. Документацию для модулей contrib в 8.4 .

Для Pg 9.1 и новее вместо этого прочтите текущие документы contrib и CREATE EXTENSION. Эти функции не существуют в 9.0 или более ранних версиях, таких как ваша 8.4.

Если вы используете упакованную версию PostgreSQL, вам может потребоваться установить отдельный пакет, содержащий модули contrib и расширения. Найдите в вашей базе данных менеджера пакетов «postgres» и «contrib».

Крейг Рингер
источник
6
@advocate. Вы используете дистрибутив PostgreSQL, так что вы должны иметь возможность использовать его apt-get install postgresql-contribили подобное. Попробуйте apt-cache search postgresql |grep contribнайти название пакета, который вы хотите.
Крейг Рингер,
2
sudo apt-get install postgresql-contrib успешно запущен. Тогда мне нужно было запустить psql -d dbname -f SHAREDIR / contrib / module.sql, и теперь это работает !!! выберите uuid_generate_v1 (); возвращает 1 сейчас и сейчас. Спасибо!
anon58192932
5
Обратите внимание, что если вы не установите postgresql-contribпакет, вы получите сообщение об ошибке: ОШИБКА: не удалось открыть файл управления расширением "/usr/share/postgresql/9.3/extension/uuid-ossp.control": такого файла или каталога нет
Дрю Ноакс
1
Я разместил этот комментарий как строку с ошибкой в ​​Google. Также он дает конкретное имя пакета, по крайней мере, для Ubuntu.
Дрю Ноакс
2
Если вы импортировали базу данных, которая уже имеет uuid-ossp в расширениях, uuid_generate_v4 () может не работать. Если это так, просто удалите расширение и создайте его снова, и оно должно работать.
Драгос Русу
304

Без расширений (чит)

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

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

(работает как минимум в 8.4)

  • Спасибо @Erwin Brandstetter за clock_timestamp()объяснение.

Если вам нужен действительный v4 UUID

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

введите описание изображения здесь * Спасибо @Denis Stafichuk @Karsten и @autronix


Также в современном Postgres вы можете просто разыграть:

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

ZuzEL
источник
5
Чтобы следить за своим PS: ВЫБЕРИТЕuuid_in(md5(random()::text || now()::text)::cstring);
Blaskovicz
4
@MattDiPasquale Вероятно, ни в каком смысле «лучше», чем использование uuid-ossp, но я, например, работаю над экземпляром PostgreSQL, где у меня нет достаточных привилегий для установки расширения.
Стефан Хаберл
25
@JosephLennox: clock_timestamp()это лучшая альтернатива в любом случае для этого. В отличие от now()или CURRENT_TIMESTAMPон изменчив и возвращает текущее время. SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring);Кроме того, в современном Postgres вы можете просто разыграть: SELECT md5(random()::text || clock_timestamp()::text)::uuid- не нужно больше магии. Пример использования: stackoverflow.com/a/8335376/939860
Эрвин Брандштеттер,
17
Нет. Если это действительно работает, то это просто удача. UUID имеет формат, а не просто случайные шестнадцатеричные символы, сшитые вместе. Первое число 3-й группы - это версия uuid для intance (обычно 4 в наши дни). Если ваше приложение проверяет эту цифру, чтобы узнать, с какой версией uuid она имеет дело, и сделать что-то соответственно, то оно не сработает в вашем коде.
Tuncay Göncüoğlu
7
@Tuncay Göncüoğlu: Довольно просто сгенерировать действительный UUID v4 (при использовании метода наложения строк тратится всего 2 бита случайности):select overlay(overlay(md5(random()::text || ':' || clock_timestamp()::text) placing '4' from 13) placing '8' from 17)::uuid;
Карстен
75

Ответ на Крейга Рингера правильно. Вот немного больше информации для Postgres 9.1 и позже ...

Доступно ли расширение?

Вы можете установить расширение только в том случае, если оно уже было создано для вашей установки Postgres (ваш кластер в Postgres lingo). Например, я обнаружил расширение uuid-ossp, включенное как часть установщика для Mac OS X, любезно предоставленное EnterpriseDB.com. Может быть доступно любое из нескольких десятков расширений .

Чтобы узнать, доступно ли расширение uuid-ossp в вашем кластере Postgres, запустите этот SQL, чтобы запросить pg_available_extensionsсистемный каталог:

SELECT * FROM pg_available_extensions;

Установить расширение

Чтобы установить это расширение, связанное с UUID , используйте команду CREATE EXTENSION, как показано в этом SQL:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

Осторожно: я обнаружил, что символы QUOTATION MARK вокруг имени расширения требуются, несмотря на обратное в документации.

Комитет по стандартам SQL или команда Postgres выбрали для этой команды нечетное имя. На мой взгляд, они должны были выбрать что-то вроде «INSTALL EXTENSION» или «USE EXTENSION».

Проверить установку

Вы можете убедиться, что расширение было успешно установлено в нужной базе данных, запустив этот SQL для запроса pg_extensionсистемного каталога:

SELECT * FROM pg_extension;

UUID в качестве значения по умолчанию

Для получения дополнительной информации см. Вопрос: Значение по умолчанию для столбца UUID в Postgres.

По старому

Приведенная выше информация использует новую функцию расширений, добавленную в Postgres 9.1. В предыдущих версиях мы должны были найти и запустить скрипт в файле .sql . Функция «Расширения» была добавлена, чтобы упростить установку, торгуя немного больше работы для создателя расширения за меньшую работу со стороны пользователя / потребителя расширения. Смотрите мой блог для дальнейшего обсуждения.

Типы UUID

Кстати, код в вопросе вызывает функцию uuid_generate_v4(). Это генерирует тип, известный как Версия 4, где почти все из 128 битов генерируются случайным образом. Хотя это подходит для ограниченного использования на меньшем наборе строк, если вы хотите практически исключить любую возможность столкновения, используйте другую «версию» UUID.

Например, оригинальная версия 1 сочетает в себе MAC-адрес хост-компьютера с текущей датой-временем и произвольным числом, вероятность коллизий практически равна нулю.

Для получения дополнительной информации см. Мой ответ на соответствующий вопрос.

Базилик Бурк
источник
1
И вы также можете использовать, CREATE EXTENSION IF NOT EXISTS ...если вы не уверены и не хотите проверять (например, в сценарии)
Uwe Allner
2
UUID версии 4 подходит практически для любого набора данных размера, а не только для «ограниченного использования на небольших наборах строк». Вы должны будете генерировать 1 миллиард UUID в секунду в течение примерно 85 лет (или около 45 миллионов терабайт данных, в тысячи раз больше, чем самые большие базы данных сегодня), чтобы даже иметь вероятность коллизии в 50%. Если вы не являетесь АНБ, Версия 4 хороша для любых целей. Версия 1, с другой стороны, страдала от того факта, что MAC-адреса назначались последовательно (и часто были подделаны или недоступны), что является частью того, почему были введены более поздние версии.
Джаз
1
@BasilBourque Проблема с v1 не в вероятности столкновения при правильной реализации, а в вероятности неправильной реализации. Как говорит Википедия: «Уникальность UUID версий 1 и 2 ... также зависит от того, правильно ли производители сетевых карт присваивают уникальные MAC-адреса своим картам, что, как и другие производственные процессы, подвержено ошибкам». Кроме того, в некоторых контейнерных или виртуализированных средах истинные MAC-адреса от базового оборудования недоступны. Если многие контейнеры имеют одинаковый MAC, но имеют собственные счетчики clockseq, их UUID v1 могут конфликтовать.
Джаз
1
@BasilBourque Слабые места в v1, однако, не главное в моем комментарии. Ваш оригинальный ответ подразумевает, что v4 не подходит для больших наборов данных из-за более высокой вероятности столкновения, чем v1. Это вводит в заблуждение и, возможно, ложно, хотя трудно вычислить вероятность столкновения для v1, потому что это зависит от реализации.
Джаз
1
@BasilBourque Например, проект node-uuid вычисляет вероятность того, что их счетчики clockseq будут одинаковыми (чтобы два процесса генерировали одинаковую последовательность vUID U1) как 1 в 4.6e18. Да, это крошечно, но гораздо более вероятно, чем вероятность немедленного столкновения в v4, которое равно 1 в 5.3e36. Очевидно, что чем дольше вы генерируете UUID v4, тем больше вероятность возникновения коллизии, что неверно для v1, но вам придется сгенерировать 1,52 млрд. UUID v4, прежде чем вероятность коллизии превысит вероятность реализации узла v1. У большинства людей нет 1,52 миллиарда записей на таблицу.
Джаз
61

pgcrypto расширение

Начиная с Postgres 9.4, pgcryptoмодуль включает gen_random_uuid()функцию. Эта функция генерирует один из типов UUID версии 4 на основе случайных чисел .

Получить модули contrib, если они еще не доступны.

sudo apt-get install postgresql-contrib-9.4

Используйте pgcryptoмодуль.

CREATE EXTENSION "pgcrypto";

gen_random_uuid()Функция в настоящее время должно доступна;

Пример использования.

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


Цитата из Postgres doc оuuid-ossp модуле.

Примечание: если вам нужны только случайно сгенерированные (версия 4) UUID, рассмотрите возможность использования функции gen_random_uuid () из модуля pgcrypto.

brillout
источник
3
Да, но смотрите также blog.starkandwayne.com/2015/05/23/… где они предупреждают о фрагментации и предлагают вместо этого uuid-ossp.
Малик А. Руми
3
На самом деле, смотрите postgresql.org/message-id/… где разоблачена проблема фрагментации uuid в Postgres
Боб Кочиско
Но у postgres есть кластеризованные индексы в последней версии, что делает публикацию, связанную в приведенном выше комментарии, неубедительной и неправильной, и мы возвращаемся к квадрату 1.
Майкл Гольдштейн
1
@MichaelGoldshteyn: нет, Postgres никак не группировались индексы (по состоянию на Postgres 12)
a_horse_with_no_name
3
ALTER TABLE table_name ALTER COLUMN id SET DEFAULT uuid_in((md5((random())::text))::cstring);

Прочитав ответ @ ZuzEL, я использовал приведенный выше код в качестве значения по умолчанию для идентификатора столбца, и он работает нормально.

Паоло Фернандес
источник
1

Предстоящий PostgreSQL 13 будет изначально поддерживать gen_random_uuid () без необходимости включать какие-либо расширения:

PostgreSQL включает одну функцию для генерации UUID:

gen_random_uuid ()  uuid

Эта функция возвращает UUID версии 4 (случайный). Это наиболее часто используемый тип UUID и подходит для большинства приложений.

ДБ <> Fiddle Demo

Лукаш Шозда
источник