Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP][MySQL] Problem z pobieraniem dużej ilości danych
Forum PHP.pl > Forum > Przedszkole
progresmedia
Witam,

mam następujący problem:

chcę wyświetlić trochę rekordów z bazy i teraz tak:

jeżeli wyświetlam do 2000 rekordów to wszystko jest OK.

Jeżeli chcę wyświetlić > 2000 rekordów, wyskakuje komunikat:

Kod
<h1>Internal Server Error</h1>  The server encountered an internal error or misconfiguration and was unable to complete your request


Znacie może jakiś sposób na obejście tego?

Próbowałem zwiększyć 'max_execution_time', ale niestety efekt został ten sam.

Od razu mówię że wolałbym uniknąć porcjowania zapytań i chciałbym wyświetlić wszystkie rekordy na jednej stronie.
Spawnm
albo set_time_limit(); albo zrób pager .
progresmedia
Próbowałem set_time_limit(), bez efektu.

Pager? A dokładniej?smile.gif
Spawnm
pager/paginacja/stronicowanie ... dzielenie treści na strony ...
progresmedia
No właśnie tego chcę uniknąć.
thek
W pierwszym poście napisał, że nie chce porcjować zapytania, więc stronnicowanie raczej odpada. Ja bym się zastanawiał nad ustawianiem jednak set_time_limit co jakiś określony czas ( co ileś iteracji ) wewnątrz pętli. Teoretycznie powinno to resetować licznik działania skryptu. Stwarza też narzut czasowy niestety. Z każdą iteracją bowiem byłby if i inkrementacja jakiegoś licznika, czyli minimum 2 dodatkowe cykle zegara co przejście pętli. Mało w porównaniu do całości czasu trwania skryptu, więc można się skusić i sprawdzić. Choć myślę, że jednak bez jakiegoś sensownego ograniczenia liczby rekordów nie ma co tego ruszać, bo obejście max_execution_time bez porcjowania, choćby niejawnego nie jest możliwe. Ja w newsletterze dla dużej liczby użytkowników zrobiłem rekurencję gdzie skrypt wywoływał sam siebie po pewnym czasie, ale tego typu rozwiązanie jest bezsensowne tutaj.
progresmedia
Próbowałem już set_time_limit(), zrobiłem coś takiego:
Kod
    ini_set('max_execution_time', 1000);
    $sql = mysql_query("SELECT newsletter_id, email FROM wp_newsletter_baza ORDER BY newsletter_id DESC");
    while(list($newsletter_id, $email) = mysql_fetch_row($sql)) {
        /* KOD */
        $b++;
        if($i == 4) {
            ?></tr><tr><?
            $i = 0;
        }
        if($b == 500) {
            set_time_limit(120);
            $b = 1;
        }
    }


Jednak skrypt na to nie reaguje (dalej pojawia się błąd).
thek
Skoro to wysyłanie newslettera, co podejrzewałem, to najlepiej dać sobie spokój z wyświetlaniem czegokolwiek na ekranie i poporcjować dane w rekurencji oraz zapomnieć, że się odpaliło skrypt, a najlepiej uruchamiać go w nocy cronem.
Ja mam mniej więcej tak to rozwiązane:
W bazie mam przy użytkowniku newslettera pole, będące datą, kiedy ostatnio skrypt newslettera próbowałem na nim wykonać, sam skrypt puszczam codziennie, ale mogę i nawet co 10 minut, bo nie leci po całej bazie w takim wypadku.

Plik 1:
Kod
a) ignoruję zakończenie połaczenia przez usera ( odpalam crona, a nie przeglądarkę ) - ignore_user_abort(true);
b) Pobieram z bazy pakiet X userów newslettera, którzy mają datę (Y-m-d) mniejszą niż obecna,
c) w razie braku userów killuję skrypt exitem
d) wysyłam im maile,
e) update daty na dzisiejszą robię tym z paczki pobranym,
f) opcjonalnie mogę skillować ale nie jest to potrzebne.


Jak widać w takiej sytuacji nigdy tego samego dnia nie trafię dwa razy tego samego usera bo po każdym przejściu zmniejsza mi się liczba userów z datą mniejszą od obecnej, aż do momentu, gdy nie ma juz nikogo takiego. To ważne, bo bez update'u pola daty, skrypt w rekurencji wykonywałby się w nieskończoność, wciąż dla tych samych X użytkowników.

Plik 2:
  1. if(!$id = mysql_connect('host','user','pass'))
  2. die('Błąd połączenia do bazy danych MySQL.');
  3. mysql_query("SET CHARSET charset;");
  4. $result = mysql_fetch_array( mysql_query( "SELECT count( user ) AS ile FROM newsletter WHERE data < CURDATE() ") );
  5. if($result['ile'] == 0 ) {
  6. $handle = fopen('newsletter.log','a');
  7. fwrite($handle, date('Y-m-d')." Koniec wysyłki newslettera.<br />");
  8. fclose($handle);
  9. } else {
  10. sleep(x sekund);
  11. file_get_contents('ścieżka_do_pliku_pierwszego');
  12. file_get_contents('ścieżka_do_pliku_drugiego_czyli_tego');
  13. }

Jak widać ustawiam na wszelki wypadek set time limit i user abort, łączę się z bazą i pobieram liczbę userów z datą mniejsza niż aktualna. Jeśli jest w wyniku jest zero zapisuję sobie w logu, że skrypt w tym dniu się zakończył. Jeśli jest takich userów więcej, to usypiam skrypt na ileś sekund, po czym wywołuję skrypt wysyłki porcji maili i... samego siebie oraz killuję tę instancję. W efekcie działa już kolejny "wątek" w rekurencji aż do momentu, gdy serwer nie przetworzy wszystkich rekordów. Aby to zauważyć nie można polegać na przeglądarce, gdyż ona po pewnym czasie zamknie połączenie z serwerem i wywali, że skrypt przekroczył czas, gdyż widzi ona tylko wywołanie pierwszej instancji, która już zapewne skillowana została i działa już w tle przynajmniej 2 lub 3 winksmiley.jpg Najlepiej sobie logować do pliku na serwerze poczynania skryptu, czyli albo w pliku1 lub w warunku else pliku2 coś wpisywać do loga smile.gif Ja testowałem poprzez wpisywanie do niego czasu. Działał on znacznie przekraczając owe 30s i działał wiele minut zanim zakończył działanie, gdyż ustawilem dłuższy czas w sleepie by nie zajechać serwera i dawać mu czas na wykonywanie innych działań. Ważne jest by dobrze napisać kod w plik1, bo zastosowanie rekurencji takiej jak pokazałem uruchamia co chwilę skrypt, którego serwer nie ma jak zatrzymać, gdyż spełnia wszystkie warunki nieprzekraczalności czasu wykonania wywołując się w kolejnych wątkach. Jeśli ktoś więc nie napisze go dobrze i nie przetestuje na localu to może mieć niemiłą niespodziankę na serwerze publicznym.
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.