Эффективная генерация уникальных ключей для записей в базе данных - PullRequest
7 голосов
/ 11 марта 2012

Я сейчас разрабатываю прототип системы регистрации.Это очень упрощенно и, по сути, это просто форма .NET, которая записывается в MongoDB.

То, с чем я застрял, - это эффективный способ создания уникального идентификатора / ключа для каждого пользователя.Эти идентификаторы должны быть удобны для человека, поэтому что-то вроде буквенно-цифровой строки длиной 7 символов, например A1B2C3X.

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

Моя идея состоит в том, чтобы предварительно вычислить набор уникальных идентификаторов и сохранить их в другой базе данных.Затем, когда мне нужно добавить новую запись в базу данных пользователей, я могу «вытолкнуть» идентификатор из моей базы данных идентификаторов (в постоянном времени) и узнать, что он еще не существует в базе данных пользователей без необходимости его поиска.

Я уверен, что кто-то должен был сделать что-то подобное раньше.Есть ли способ лучше?Я не знаю, почему я так борюсь с этим.Ваш вклад очень ценится.

1 Ответ

11 голосов
/ 11 марта 2012

Генерация случайной строки в приложении и проверка ее уникальности - неплохое решение. Не беспокойтесь о том, что это неэффективно, это не так - и определенно не по сравнению с альтернативами. Это, безусловно, будет быстрее, чем запуск db.user.count() или ведение отдельной таблицы с предварительно рассчитанными идентификаторами. Вам просто нужно сделать это правильно.

Прежде всего, как часто будут создаваться новые пользователи? Вероятно, не очень часто по сравнению с другими вещами, так что на самом деле все обсуждение эффективности является спорным. Во-вторых, с 7 символами A-Z, 0-9, это диапазон 36 ^ 7 или где-то около 78 миллиардов. Пройдет некоторое время, прежде чем вы начнете видеть столкновения, если не сказать больше.

Если вы просто сделаете это так, это не повлечет за собой снижения производительности, если не произойдет столкновение (что крайне маловероятно):

  • Создать уникальный идентификатор пользователя
  • Вставьте ваш пользовательский объект, используя идентификатор пользователя в качестве значения _id
  • Проверка на наличие дублирующихся ошибок ключа (как это сделать, зависит от языка и драйвера, но может включать выполнение команды getLastError).
  • При повторяющейся ошибке ключа начните заново, сгенерировав новый идентификатор пользователя

Таким образом, в случае столкновения будет только дополнительная работа (и я действительно, очень хочу подчеркнуть, как невероятно маловероятно это будет).

Существует еще один способ создания уникального идентификатора пользователя: взять текущую метку времени UNIX (с точностью до секунды), добавить хэш имени хоста, затем идентификатор процесса и, наконец, текущее значение счетчика. Фактически именно так генерируется ObjectId Монго и гарантирует, что вы можете генерировать столько объектов в секунду на процесс, сколько и максимальное значение вашего счетчика (которое в Монго составляет 3 байта, то есть 16 миллионов). Посмотрите документы по ObjectId, если вам интересны подробности: http://www.mongodb.org/display/DOCS/Object+IDs

Он обладает свойством, которое идентифицирует ваши идентификаторы пользователей в порядке их создания, но его длина составляет 12 байтов, поэтому, к сожалению, немного длиннее, чем ваши 7 символов. Вы можете использовать тот же метод и пропустить имя хоста / pid и сократить счетчик (который также может быть случайным числом) до двух байтов, тогда вы будете уменьшены до 6 байтов, которые, вероятно, могут быть сжаты примерно до 9 символы AZ, 0-9.

...