Подтвердить что ты не робот

Генерируя последовательный пятизначный буквенно-цифровой идентификатор

Общий обзор:

Функция ниже выплевывает случайный идентификатор. Я использую это, чтобы предоставить псевдоним подтверждения идентификации записи. Тем не менее, мне пришлось проверять наличие столкновения (как бы маловероятно), потому что мы используем только пятизначную длину. С допустимыми символами, перечисленными ниже, это составляет около 33 миллионов плюс комбинации. В конце концов мы получим до пяти миллионов записей, поэтому столкновение становится проблемой.

Проблема:

Проверка псевдонимов dupe неэффективна и ресурсоемкая. Пять миллионов записей - это много для поиска. Особенно, когда этот поиск выполняется одновременно разными пользователями.

Мой вопрос:

Есть ли способ "автоматически увеличивать" комбинации, разрешенные этой функцией? Значит, мне нужно искать только последний псевдоним записи и перейти к следующей комбинации?

Признанные ограничения:

Я понимаю, что код будет значительно отличаться от приведенной ниже функции. Я также понимаю, что mysql имеет функцию автоматического увеличения для числовых идентификаторов, но для проекта требуется пятизначный псевдоним с допустимыми символами "23456789ABCDEFGHJKLMNPQRSTUVWXYZ". Мои руки связаны с этой проблемой.

Моя текущая функция:

 public function random_id_gen($length)
 {
     $characters = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
     $max = strlen($characters) - 1;
     $string = '';

     for ($i = 0; $i < $length; $i++) {
         $string .= $characters[mt_rand(0, $max)];
     }

     return $string;
 }
4b9b3361

Ответ 1

Почему бы просто не создать уникальный индекс в столбце псевдонима?

CREATE UNIQUE INDEX uniq_alias ON MyTable(alias);

в этот момент вы можете попробовать вставить/обновить и, если он вернет ошибку, сгенерируйте новый псевдоним и повторите попытку.

Ответ 2

Что вам действительно нужно сделать, это преобразовать с базы 10 на базовый strlen($characters).

PHP поставляется со встроенной функцией base_convert, но не делает именно то, что вы хотите, поскольку оно будет использовать числа ноль, одно и букву "o", которых у вас нет в вашей версии. Поэтому вам понадобится функция для сопоставления значений от base_convert от/до ваших значений:

function map_basing($number, $from_characters, $to_characters) {
    if ( strlen($from_characters) != strlen($to_characters)) {
       // ERROR!
    }

    $mapped = '';
    foreach( $ch in $number ) {
       $pos = strpos($from_characters, $ch);
       if ( $pos !== false ) {
          $mapped .= $to_characters[$pos];
       } else {
          // ERROR!
       }
    }

    return $mapped;
}

Теперь у вас есть это:

 public function next_id($last_id)
 {
    $my_characters = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
    $std_characters ='0123456789abcdefghijklmnopqrstuv';

    // Map from your basing to the standard basing.
    $mapped = map_basing($last_id, $my_characters, $std_characters);

    // Convert to base 10 integer and increment.
    $intval = base_convert($mapped, strlen($my_characters), 10);
    $intval++;

    // Convert to standard basing, then to our custom basing.
    $newval_std = base_convert($intval, 10, strlen($my_characters));
    $newval = map_basing($newval_std, $std_characters, $my_characters);


    return $newval;
 }

Могут быть некоторые синтаксические ошибки, но вы должны получить его суть.

Ответ 3

Вы можете свернуть собственный автоинкремент. Вероятно, это было бы довольно неэффективно, хотя вам нужно было выяснить, где в процессе ваш прирост. Например, если вы назначили позицию в своей случайной строке как целое число и начинаете с (0) (0) (0) (0) (0), которая будет равна 22222 в качестве идентификатора. Затем, чтобы получить следующий, просто увеличьте последнее значение до (0) (0) (0) (0) (1), которое переведет на 22223. Если последний получает вашу длину строки, то сделайте его 0 и увеличивайте второе и последнее и т.д. Это не точно случайное, но оно будет увеличиваться и быть уникальным.