Генерация уникальных номеров счетов – рекурсивный вызов

StackOverflow https://stackoverflow.com/questions/98497

  •  01-07-2019
  •  | 
  •  

Вопрос

Привет, мне нужно сгенерировать 9-значные уникальные номера счетов.Вот мой псевдокод:

function generateAccNo()

    generate an account number between 100,000,000 and 999,999,999

    if the account number already exists in the DB 
        call generateAccNo()    /* recursive call */
    else
        return new accout number
    end if

end function

Кажется, что функция работает хорошо, однако меня немного беспокоит рекурсивный вызов.

Вызовет ли это какие-либо утечки памяти (PHP 5 под Apache)?

Является ли это приемлемым способом решения этой проблемы?

Спасибо за ваш вклад.

Это было полезно?

Решение

Вы понимаете, что это вполне может вызвать переполнение стека, верно?По мере увеличения количества клиентов увеличивается вероятность не найти приемлемый номер счета.

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

Извините за резкость, но ваше решение — ужасный способ решить проблему.Он будет использовать тонны памяти (поскольку стек, возможно, будет расти бесконечно) и будет совершать тонны дорогостоящих вызовов к базе данных.

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

Другие советы

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

.ГУИД

Если требуется действительно уникальный идентификатор с минимальными усилиями, рассмотрите GUID, ваша БД, скорее всего, сможет назначить его для вас при вставке, если не создать его в коде.Он гарантированно уникален, хотя и не очень удобен для пользователя.Однако в сочетании с последовательным AccountRecordId, сгенерированным БД при вставке, вы получите надежную комбинацию

.Составной ключ:Случайный + Последовательный

Один из способов удовлетворить все потребности, хотя на первый взгляд он кажется немного неуклюжим, — это создать составной номер счета из последовательного ключа базы данных из 5 (или более) цифр, а затем еще 5 случайных цифр.Если случайное число было продублировано, это не имело бы значения, поскольку последовательный идентификатор гарантировал бы уникальность всего номера счета.

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

function generateAccNo()

    generate an account number between 100,000,000 and 999,999,999

    while ( the account number already exists in the DB ) {
         generate new account number;
    }
    return new account number

end function

Однако случайная генерация и тестирование — неоптимальный подход к генерации уникальных номеров счетов, если этот код предназначен для чего-то другого, кроме игрушки.

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

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

Последовательное создание номеров счетов представляет собой угрозу безопасности — вам следует найти другой алгоритм для этого.

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

Кроме того, я должен отметить, что накладные расходы на обработку или риски рекурсии или итерации, настоящая проблема — это детерминизм и накладные расходы на повторение запросов к базе данных.Мне нравится решение TheZenker: случайное + последовательное.Гарантировано создание уникального идентификатора без добавления ненужных накладных расходов.

Здесь не нужно использовать рекурсию.Простой цикл будет таким же быстрым и будет занимать меньше места в стеке.

Вы можете поместить это в цикл while:

function generateAccNo()

    while (true) {    

      generate an account number between 100,000,000 and 999,999,999

      if the account number already exists in the DB 
          /* do nothing */
      else
          return new accout number
      end if
    }

end function

Почему нет:

lock_db
do
    account_num <= generate number
while account_num in db

put row with account_num in db

unlock_db

Почему бы не позволить базе данных справиться с этим?В SQL Server вы можете просто иметь столбец идентификаторов, начинающийся с 100000000.Или вы можете использовать sql в любой имеющейся у вас базе данных.Просто получите максимальный идентификатор плюс 1.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top