Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MySQL][PHP] Wygenerowanie miliona unikalnych kodów ;)
Forum PHP.pl > Forum > Przedszkole
peter13135
Jak w temacie, w jaki sposób to zrobić ?

kod wygenerować potrafię, dodać go do bazy o dziwo też. Ale ponieważ tego ma być dokładnie milion, to dodanie tego w ten sposób:
  1.  
  2. $kod = generujKod();
  3.  
  4. $istnieje = sprawdzCzyKodIstniejeWBazie();
  5.  
  6. if($istnieje)
  7. {
  8. dodajKodDoBazy();
  9. }
  10.  


Moim zdaniem jest nieco kiepskim pomysłem.

Myślałem o tym, by generować powiedzmy 100 kodów i sprawdzać, które z nich istnieją, myślę,że takie hurtowe wysyłanie pójdzie nieco szybciej.

A co Wy proponujecie ? wink.gif
zamper
A może tak:
  1. $kod = sha1( time().microtime().''.($jakasLosowaLiczba * $jakasInnaLosowaLiczba / $jakasJeszczeInnaLosowaLiczba) );

Potem to puszczasz w pętli która wstawia to do bazy smile.gif

To co masz z funkcji hashującej możesz w dowolnej kolejności mieszać, a kody zawszę będą mieć 40 znaków i będę na 99.(9)% unikalne wink.gif
peter13135
Pisałem, że kod potrafię wygenerować. I zrobię to innym sposobem (choćby dlatego, że chce mieć też duże znaki, których sha1 chyba nie posiada)
Problem jest w tym, żebby to wszystko wprowadzić do bazy.

Tablica w php chyba nie przetrzyma miliona rekordów (chyba, że się mylę);
zamper
Cytat
Potem to puszczasz w pętli która wstawia to do bazy

Albo możesz też zrobić zapytania typu:
  1. INSERT INTO kody VALUES ('sfdwfw'), ('wfwfe'), ('wefegf');
Wazniak96
a myslales o przepuszczeniu tego przez pętle for i dodawac np po 10000 rekordow do bazy .?
peter13135


Cytat
INSERT INTO kody VALUES ('sfdwfw'), ('wfwfe'), ('wefegf');


Aby takie zapytanko wygenerować, musze mieć najpierw tablicę z tymi kodami.

Moja super maszyna za pomocą mojego super kodu w PHP, jest w stanie wygenerować jakieś 32k kodów w ciągu pierwszej minuty, zapisując je do tablicy i sprawdzając czy taki kod już istnieje. W kolejnych minuatach będzie pewnie trochę mniej generowanych kodów, bo sprawdzanie (za pomocą in_array) czy kod już istnieje będzie coraz wolniej działało wraz ze wzrostem elementów tablicy. Dlatego poszukuję lepszego rozwiązania.

Cytat
a myslales o przepuszczeniu tego przez pętle for i dodawac np po 10000 rekordow do bazy .?


Myślałem (przecież nawet o tym pisałem) ale wtedy musiałbym łączyć się z bazą i sprawdzać czy kod istnieje, co chyba trwa więcej niż sprawdzenie tego w tablicy php. Z drugiej strony, nie wiem czy jest możliwe utworzenie tak dużej tablicy
zamper
Jeżeli zależy ci na czasie to wymyśl taki algorytm tworzenie kodów, żeby się nie powtarzały.
Potem pętla na zasadzie takiej
  1. $q = 'INSERT INTO kody VALUES ';
  2. for($i=0; $i<1000000; $i++) {
  3. $q .= '("'.generujKod().'"),';
  4. }
  5. $res = $db->query($q);


Do funkcji generujKod możesz przekazać licznik pętli i na podstawie jego utworzyć kod wink.gif
peter13135
Niestety, takiego algorytmu stworzyć nie potrafię (który byłby nie do rozszyfrowania przy okazji)
zamper
Cytat
Pisałem, że kod potrafię wygenerować. I zrobię to innym sposobem (choćby dlatego, że chce mieć też duże znaki, których sha1 chyba nie posiada)

No to jak w końcu dry.gif

Algorytm najlepiej zrób na podstawie time, microtime, rand. Potem to wszystko opakuj w sha1. Później możesz tego hasha przetransformować tak, żeby co losowo wygenerowany numerek (albo licznik pętli) robiło większą literę smile.gif
peter13135
1.Pisałem, że potrafię wygenerować losowy ciąg znaków (co nazywałem kodem), a nie potafię stworzyć algorytmu do generowania kodów, które by się nie powtarzały.

2. A jak zagwarantujesz, że Twój sposób zwróci mi milion unikalnych kodów ? Pozatym, długość tego mojego kodu ma być równa 10.
Wazniak96
Kiedys na necie znalazlem taki oto kodzik do tworzenia kodow, moze Ci się kolego przyda wink.gif
  1. $letters = 'abcdefghijklmnopqrstuvwxyz';
  2. $digits = '0123456789';
  3.  
  4. function password_letters($length) {
  5. global $letters;
  6. $array = str_split( $letters );
  7. shuffle( $array );
  8. return implode( array_slice( $array, 0, $length ) );
  9. }
  10.  
  11. function password_digits($length) {
  12. global $digits;
  13. $array = str_split( $digits );
  14. shuffle( $array );
  15. return implode( array_slice( $array, 0, $length ) );
  16. }
  17.  
  18. function password_combined($length) {
  19. global $letters, $digits;
  20. $array = str_split( $letters.$digits );
  21. shuffle( $array );
  22. return implode( array_slice( $array, 0, $length ) );
  23. }
  24.  
  25. $haslo = password_combined(6);
peter13135
To spytam trochę inaczej. Mogę dać do tabeli w bazie klucz UNIQUE.

Czy jest możliwość, wykonania zapytania typu

[sql]INSERT INTO `codes` VALUES ('kod1'), ('jakiś inny kod'), (...)[/code]
Załóżmy, że ma on 10k kodów i jeśli powiedzmy powtórzy się 100 kodów, to zamiast errora "duplicate entry..." po prostu pominie te duplikaty i doda 9900 kodów ? wink.gif
//edit:: już wiem tongue.gif

edit://
@up, dzięki za chęci, ale się nie przyda.
zamper
Mój mały algorytm tworzy co prawda 40 znakowe kody, ale na pewno będę one unikalne, bo są zależne od czasu i kilku liczb losowych oraz ewentualnie licznika pętli

Co do tego, żeby kody miały tylko 10 znaków to już trudniejsza sprawa, ale jeżeli mają one być do potwierdzenia rejestracji konta to 40 a 10 znaków nie robi takiej różnicy, bo i tak kod jest wklepany w linku
peter13135
Nie mają być do potwierdzenia rejestracji konta, uwierz mi, że do tego celu nie potrzebował bym generować tyle kodów jednocześnie.
zamper
Możesz w takim razie utworzyć zmienną zawierającą wszystkie znaki dostępne w kodzie (a-z A-Z 0-9) i w pętli 10 razy za pomocą liczby losowanej w każdej iteracji wyciągać jakiś znak w tej zmiennej. Wadą tego rozwiązania jest możliwość powtórzenia się kodów.
Kużdo
Ale kombinujecie. Tworzysz unikalną kolumnę w bazie, a przy wrzucaniu swoich rekordów ignorujesz duplikaty w sposób:
  1. INSERT IGNORE INTO `nazwa_tabeli` ...


A najlepiej jakbyś zrobił sobie formularz do wpisania ilości generowanych rekordów, bo przyda się później. Pod koniec skryptu pobierasz ilość wszystkich rekordów:
  1. SELECT COUNT(`id`) AS `ile` FROM `nazwa_tabeli`


i wyświetlasz sobie ile masz już rekordów, dzięki temu będziesz wiedział ile wpisać w pole formularza jeszcze.
peter13135
Drogi Kolego zamper. Pisałem w pierwszym poście, o tym że jestem w stanie wygenerować sobie kod (w którymś z następnych postów dodałem, że ma mieć 10 znaków). I z mojego pierwszego postu wynika, że aby utworzyć za pomocą mojego sposobu milion unikalnyh kodów, muszę za każdym razem sprawdzać, czy wcześniej takiego kodu nie wygenerowałem. Zauważ więc, że Twój post nic nowego nie wnosi do tematu.


Zrobiłem kod, który generuje 1000 kodów, następnie wrzuca je do bazy, a baza danych zapisuje tylko te, których jeszcze nie ma w bazie (za pomocą INSERT IGNORE). Działąło by super.... tylko, że baza danych przyjmuje tylko 32768 rekordów. Czy jest na to jakiś sposób ?


@up. O tym, że dowiedziałem się, że jest coś takiego jak INSERT IGNORE dowiedziałęm się jakieś 20 minut temu (patrz post nr 12)
dr_NO
Za MySQL Change Log
Cytat
Support for large databases. We use MySQL Server with databases that contain 50 million records. We also know of users who use MySQL Server with 200,000 tables and about 5,000,000,000 rows.

Jakiego typu masz pola w bazie? Może używasz typu który ma ograniczenia?
Kużdo
Nie zauważyłem tego wink.gif

Przyjmuje Ci MAKS 32768 rekordów, czy w jednej paczce tyle? Bo nie do końca zrozumiałem to co napisałeś. Miałem w sumie wrzucić tutaj przykładowy kod do poprzedniego postu, ale nie wiem czy jest Ci jeszcze potrzebny.
peter13135
id to big int

typ bazy to MyIsam, przed chwilą miałem innoDb, ale na obu mam ten limit.

Paczki mam po 10k

Baza ma limit ~33k (2^15)
Kużdo
Nie wiem co to za limit, ja mam testową tabelę z polami id(unsigned int) i kod(varchar:10) i mam już ponad 500 tys. rekordów.
peter13135
a jaki typ bazy danych ? (jak robię nową bazę to mam "mechanizm składowania"
Kużdo
InnoDB
dr_NO
Ograniczenia serwera? Gdzie testujesz?
Cytat
bigint largest value is 18,446,744,073,709,551,615
peter13135
testuje na localu. Jakimś cudem udało mi się upchać ~83 k rekordów. (tzn. jak sortuję po id DESC, to największe id to właśnie koło 83k)

Takie zapytanko
  1. SELECT count( id )
  2. FROM `codes`

Pokazuje mi jednak 32768

Wszystko testuje na swoim localu najnowszy xampp (tzn. najnowszy był jak go ssałem biggrin.gif ) + windows xp sp3
Kużdo
Spróbuj tego (chociaż nie wiem co za różnica, ale może coś źle robisz):

  1. CREATE TABLE IF NOT EXISTS `kody` (
  2. `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `kod` varchar(10) NOT NULL,
  4. PRIMARY KEY (`id`),
  5. UNIQUE KEY `kod` (`kod`)
  6. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;


W core.php połączenie z bazą etc.

  1. <form action="" method="post">
  2. <input type="text" name="ile" /> <input type="submit" value="ok" />
  3. </form>
  4. <?php
  5. if(isset($_POST['ile']))
  6. {
  7. require_once 'core.php';
  8.  
  9. $query = "INSERT IGNORE INTO `kody` (`kod`) VALUES ";
  10.  
  11. for($i = 0; $i < $_POST['ile']; $i++)
  12. {
  13. $query .= "('".substr(hash('sha1', microtime()), 0, 10)."'), ";
  14. }
  15.  
  16. $query = trim($query, ', ');
  17.  
  18. $query .= ';';
  19.  
  20. $result = mysql_query($query) or die(mysql_error());
  21.  
  22. $ile = "SELECT COUNT(`id`) as `ile` FROM `kody`";
  23. $ile = mysql_query($ile);
  24. $ile = mysql_fetch_assoc($ile);
  25.  
  26. echo '<br /><br />W bazie jest juz: '.$ile['ile'].' rekordow.';
  27. }
  28. ?>
peter13135
yeah, udało się wink.gif

Taka funkcja
  1. function generujKod()
  2. {
  3. $str = '';
  4. for($i =0; $i<10; $i++)
  5. {
  6. $str.= $this->chars[rand(0,57)];
  7. }
  8. if(!in_array($str,$this->codes ))
  9. {
  10. $this->codes[] = $str;
  11. }
  12. }


Generowała ~16k unikalnych znaków, więcej nie chciała.

funkcję rand() zamieniłem na
  1. (microtime()*rand(1,99999))%58

I teraz jest gites, dociągnąłem do miliona wink.gif
Kużdo
A po co w tym masz jeszcze sprawdzanie czy w tablicy znajdują się już takie wartości? Pisałem o tym wcześniej i też w moim przykładzie nigdzie nie używam tablic, a to dlatego, że robisz bezsensowną pracę. Masz nałożone UNIQUE w tabli, więc sprawdzanie tablicy po stronie PHP już nie jest potrzebne.
peter13135
Ponieważ na początku przjąłem inną koncepcję (tzn. wygenerowanie kodów wszystkich i następnie ich załadowanie) potem się to zmieniło, a kod został. To wielkiego znaczenia nie ma, bo wygenerowaie tych kodów miałó być jednorazowe.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.