С Rails 5, какой самый эффективный способ генерировать и использовать «hash_id» в стиле Basecamp (вместо последовательных идентификаторов строк) для каждой новой записи? - PullRequest
0 голосов
/ 25 апреля 2018

То, что я собираюсь сделать, это URL, очень похожий на Basecamp :

https://3.basecamp.com/4000818/buckets/7452203/message_boards/1039416768

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

def set_hash_id
    hash_id = nil
    loop do
      hash_id = SecureRandom.urlsafe_base64(9).gsub(/-|_/,('a'..'z').to_a[rand(26)])
      break unless self.class.name.constantize.where(:hash_id => hash_id).exists?
    end
    self.hash_id = hash_id
  end

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

Буду признателен за любой вклад в методы для генерации непоследовательного идентификатора записи.Меня не интересуют UUID, так как я не выношу неприятные URL, которые они генерируют.Кроме того, они должны быть целыми числами.В принципе, точно так же, как URL Basecamp, но без накладных расходов существует?чеки.Возможно ли, что они делают какую-то комбинацию чисел с закодированной временной меткой или что-то, чтобы гарантировать отсутствие коллизий?Я исследовал метод hashids.org , но он не генерирует хэши, содержащие только целые числа.

Я использую Postgres в качестве базы данных, если это полезно.

1 Ответ

0 голосов
/ 25 апреля 2018

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

Есть еще одна проблема, которую стоит рассмотреть:

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

У вас есть как минимум 2 варианта, чтобы справиться с этим. Оба решения также должны быть более эффективными (что является вашей главной задачей).

Перехватить нарушение ограничения уникального ключа БД при сохранении

def save
  begin
    self.hash_id = generate_hash_id
    super
  rescue ActiveRecord::RecordNotUnique => e
    # 1. you may need to check the message for the specific constraint
    # 2. you may need to implement an abort condition to prevent infinite retries
    retry
  end
end

Вы также можете сделать это в обратном вызове ActiveRecord.

Пусть БД сгенерирует ключ

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...