Pytanie generowanie sekwencyjnego pięciocyfrowego identyfikatora alfanumerycznego


Przegląd ogólny:

Poniższa funkcja wypowiada losowy identyfikator. Używam tego, aby dostarczyć alias potwierdzający do zidentyfikowania rekordu. Musiałem jednak sprawdzić kolizję (choć jest to mało prawdopodobne), ponieważ używamy tylko pięciocyfrowej długości. Z dozwolonymi znakami wymienionymi poniżej, wychodzi na około 33 miliony plus kombinacje. Ostatecznie dojdziemy do około pięciu milionów rekordów, więc kolizja staje się problemem.

Problem:

Sprawdzanie duplikatów jest nieefektywne i zasoby są ciężkie. Pięć milionów rekordów to dużo do przeszukiwania. Zwłaszcza, gdy to wyszukiwanie jest prowadzone jednocześnie przez różnych użytkowników.

Moje pytanie:

Czy istnieje sposób "automatycznego zwiększania" kombinacji dozwolonych przez tę funkcję? Czy muszę szukać aliasu ostatniego rekordu i przejść do następnej kombinacji?

Potwierdzone ograniczenia:

Zdaję sobie sprawę, że kod byłby znacznie inny niż poniższa funkcja. Rozumiem również, że mysql ma funkcję automatycznego przyrostu dla liczbowych identyfikatorów, ale projekt wymaga pięciocyfrowego aliasu z dozwolonymi znakami "23456789ABCDEFGHJKLMNPQRSTUVWXYZ". Moje ręce są związane z tą kwestią.

Moja aktualna funkcja:

 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;
 }

12
2018-06-13 20:00


pochodzenie


+1 dla dobrze zorganizowanego pytania :) - Joshua - Pendo
Ha, dzięki pendo. Społeczność SO jest niesamowita. To lekceważenie, gdy rzuca się niedbałym pytaniem. - k to the z
32 ^ 5 = 33 544 432 <50 000 000 - Gumbo
utwórz osobną tabelę z unikatowymi identyfikatorami i zaznacz, które z nich są używane (tak to rozwiązaliśmy) - Grumpy
Tgr, sądzę, że byłoby to prawdą, gdybyśmy powiedzieli "jakie jest prawdopodobne, że dwa aliasy już w bazie danych są takie same". Ponieważ jednak nazywamy alias i mówimy "jaki jest prawdopodobny kaptur, w którym znajduje się alias x w bazie danych", problem z urodzinami nie ma zastosowania. Na przykład, jeśli powiesz "jak prawdopodobne jest, że dwoje ludzi ma urodziny 04/01 w danej grupie" to nie jest to samo co "jak prawdopodobne jest to, że dwoje ludzi ma takie same urodziny w danej grupie ". - k to the z


Odpowiedzi:


Dlaczego po prostu nie utworzyć unikalnego indeksu w kolumnie alias?

CREATE UNIQUE INDEX uniq_alias ON MyTable(alias);

w tym momencie możesz wypróbować wstawkę / aktualizację i jeśli zwróci błąd, wygeneruj nowy alias i spróbuj ponownie.


5
2018-06-13 20:04



Cytując Claya Davisa: "shiiiiiiiiiiiiit". Dziękuję, proszę pana, myślę, że to najprostsze rozwiązanie. To dla ciebie efekt ponad ramieniem. - k to the z


To, co naprawdę musisz zrobić, to przekonwertować z bazy 10 na bazę strlen($characters).

PHP pochodzi z wbudowanym base_convert funkcja, ale nie robi dokładnie to, co chcesz, ponieważ będzie używać liczb zero, jedna i litera "o", których nie masz w swojej wersji. Potrzebujesz funkcji do odwzorowania wartości z base_convert od / do twoich wartości:

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;
}

Teraz, gdy już to masz:

 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;
 }

Może być tam kilka błędów składniowych, ale powinieneś to zrozumieć.


1
2018-06-13 20:32



Eric, dziękuję za dokładną odpowiedź. - k to the z


Możesz rzucić własną auto-inkrementacją. Prawdopodobnie byłoby to dość nieefektywne, ponieważ musielibyśmy się dowiedzieć, gdzie w trakcie procesu przyrost był. Na przykład, jeśli przypisałeś pozycję w losowym łańcuchu jako liczbę całkowitą i rozpoczęto od (0) (0) (0) (0) (0), które oznaczałoby 22222 jako ID. Następnie, aby uzyskać następny, po prostu zwiększ ostatnią wartość do (0) (0) (0) (0) (1), co przekłada się na 22223. Jeśli ostatnia dostaje się do długości twojego ciągu, następnie wykonaj 0 i przyrost drugi do końca, itp. Nie jest to przypadek losowy, ale byłby inkrementowany i niepowtarzalny.


0
2018-06-13 20:11