Замена последовательности случайным числом

Я хотел бы заменить некоторые из последовательностей, которые я использую для id в моем postgresql db, с помощью моего собственного генератора id. Генератор будет производить случайное число с checkdigit в конце. Итак:

SELECT nextval('customers')

будет заменено на что-то вроде этого:

SELECT get_new_rand_id('customer')

Затем функция вернет числовое значение, такое как: [1-9][0-9]{9}, где последняя цифра является контрольной суммой.

У меня есть проблемы:

  • Как сделать элемент атомарным
  • Как избежать повторного обращения к одному и тому же идентификатору дважды (это можно было бы поймать, пытаясь вставить его в столбец с уникальным ограничением, но потом его до позднего я думаю)
  • Это хорошая идея?

Примечание1. Я не хочу использовать uuid, так как он должен быть передан с клиентами, а 10 цифр намного проще общаться, чем с 36 символами uuid.

Примечание2. Функция редко вызывается с помощью SELECT get_new_rand_id(), но будет назначаться как значение по умолчанию для столбца id вместо nextval().

РЕДАКТИРОВАТЬ: Хорошо, хорошая дискуссия ниже! Вот несколько объяснений, почему:

  • Так почему бы мне переуплотить вещи таким образом? Пурпур должен скрыть первичный ключ от клиентов.

    Я даю каждому новому клиенту уникальный customerId (сгенерированный серийный номер в db). Поскольку я общаюсь с этим номер с клиентом - это довольно простая задача для моих конкурентов контролировать мой бизнес (есть другие номера, такие как счет-фактура nr и порядка nr, которые имеют одинаковые свойства). Именно этот мониторинг я хотел бы сделать немного сложнее (примечание: не невозможно, но сложнее).

  • Почему контрольная цифра?

    Прежде чем были разговоры о сокрытии серийного номера, я добавил checkdigit для заказа nr, так как в некоторых точках производства были klumbsy пальцы, и я думал, что это будет хорошей практикой, чтобы сохранить в будущем.

После прочтения обсуждения я, безусловно, могу видеть, что мой подход - это не лучший способ решить мою проблему, но у меня нет другой хорошей идеи, как ее решить, поэтому, пожалуйста, помогите мне здесь.

  • Должен ли я добавить дополнительный столбец, где я помещаю идентификатор, который я выставляю клиенту, и сохраняю его как первичный ключ?
  • Как я могу генерировать идентификатор для эффективного и эффективного использования?
  • Требуется ли checkdigit?

Ответ 1

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

Большинство криптографических шифров работают с 64-битными или более крупными блоками, но в wiki PostgreSQL есть пример процедуры PL/pgSQL для "некриптографического" шифрования, которая работает с типом (32-бит) int. Отказ от ответственности: я не пробовал использовать эту функцию самостоятельно.

Чтобы использовать его для ваших основных ключей, запустите вызов CREATE FUNCTION со страницы вики, а затем в таблицах empty выполните:

ALTER TABLE foo ALTER COLUMN foo_id SET DEFAULT pseudo_encrypt(nextval('foo_foo_id_seq')::int);

И вуаля!

pg=> insert into foo (foo_id) values(default);
pg=> insert into foo (foo_id) values(default);
pg=> insert into foo (foo_id) values(default);
pg=> select * from foo;
  foo_id   
------------
 1241588087
 1500453386
 1755259484
(4 rows)

Ответ 2

Я добавил свой комментарий к вашему вопросу, а затем понял, что должен был лучше объяснить себя... Приносим извинения.

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

Это ключ, который вы разделяете со своими клиентами, никогда не ПК. Я знаю, что есть дебаты (хотя, я не могу понять, почему), если ПК должны быть невидимыми для пользовательских приложений или нет. Современные методы проектирования баз данных и мой личный опыт, похоже, предполагают, что ПК не должны быть видимыми для пользователей. Они склонны придавать им значение, и со временем это очень плохо - независимо от того, есть ли у них контрольная цифра в ключе или нет.

Ваши соединения будут выполняться с помощью ПК. Этот другой сгенерированный ключ только предполагается использовать для поиска клиентов. Это лицо, ПК - это кишки.

Надеюсь, что это поможет.

Изменить: FWIW, мало что можно сказать о "правильном" или "неправильном" в дизайне базы данных. Иногда это сводится к выбору. Я думаю, что выбор, с которым вы сталкиваетесь, будет лучше обслуживаться, оставив ПК только и создав вторичный ключ - именно это.

Ответ 3

Я думаю, вы слишком усложняете это. Почему бы не позволить базе данных делать то, что она делает лучше всего, и позволить ей заботиться об атомарности и гарантировать, что один и тот же идентификатор не используется дважды? Почему бы не использовать тип postgresql SERIAL и получить первичный ключ с автогенерированным суррогатом, как и столбец IDENTITY целого числа в SQL Server или DB2? Используйте это вместо столбца. Плюс это будет быстрее, чем ваша пользовательская функция.

Я соглашаюсь скрыть этот суррогатный первичный ключ и использовать открытый ключ (с уникальным ограничением на него) для поиска клиентов в вашем интерфейсе.

Используете ли вы последовательность, потому что вам нужен уникальный идентификатор для нескольких таблиц? Это, как правило, указывает на необходимость переосмыслить дизайн вашей таблицы, и эти несколько таблиц, возможно, должны быть объединены в один, с автогенерированным суррогатным первичным ключом.

Также см. здесь

Ответ 4

Как вы генерируете случайные и уникальные идентификаторы - полезный вопрос, но вы, кажется, делаете встречное продуктивное предположение о том, когда их генерировать!

Я хочу сказать, что вам не нужно генерировать этот идентификатор во время создания ваших строк, потому что они по существу не зависят от вставленных данных.

То, что я делаю, является предварительным генерированием случайного идентификатора для будущего использования, таким образом, я могу взять свое собственное сладкое время и абсолютно гарантировать, что они уникальны, и нет обработки, которая будет сделана во время вставки.

Например, у меня есть таблица заказов с order_id. Этот идентификатор генерируется "на лету", когда пользователь вводит порядок, постепенно 1,2,3 и т.д. Навсегда. Пользователь не должен видеть этот внутренний идентификатор.

Затем у меня есть другая таблица - random_ids с (order_id, random_id). У меня есть рутина, которая работает каждую ночь, которая предварительно загружает эту таблицу с достаточным количеством строк, чтобы покрыть заказы, которые могут быть вставлены в следующие 24 часа. (Если я когда-либо получаю 10000 заказов за один день, у меня будет проблема - но это будет хорошая проблема!)

Этот подход гарантирует уникальность и отвлекает любую обработку от транзакции вставки и в пакетную процедуру, где она не влияет на пользователя.

Ответ 5

Лучше всего, вероятно, быть какой-то формой хеш-функции, а затем добавить контрольную сумму в конец.

Ответ 6

Если вы не используете это слишком часто (у вас нет нового клиента каждую секунду, не так ли?), тогда можно просто получить случайное число, а затем попытаться вставить запись. Просто будьте готовы повторить вставку с другим номером, когда он терпит неудачу с уникальным нарушением ограничения.

Я бы использовал числа от 1000000 до 999999 (900000 возможных номеров одинаковой длины) и проверил цифру, используя алгоритм UPC или ISBN 10. 2 контрольных цифры были бы лучше, хотя они устранили бы 99% человеческих ошибок вместо 9%.