Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

2 Stron V   1 2 >  
Reply to this topicStart new topic
> Przerzedzanie wyników na serwerze, wyciąganie co któregoś rekordu
ky3orr
post 29.03.2009, 01:50:17
Post #1





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 25.10.2004
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


Witam wszystkich!

zmagam sie z problemem pobierania danych do wykresu.
Chodzi o to, że użytkownik ma mozliwośc podania zakresu dat za jaki okres chce zobaczyć wykres.
Danych za ten okres moze byc kilka, a może być 100milionów.
Zakładam, że komponent wykresowy akceptuje powiedzmy 10000 punktów i tu pytanie:
-czy mozna skonstruować takie zapytanie, aby w przypoadku gdy liczba rekordów wyniku była większa niż 100tysięcy to wtedy wyciągnie tylko co niektóre (kwestia algorytmu wyliczającego co ile punktów pobierać rekord do wyniku - np. jakiś mod) tak, żeby tabela końcowa wracająca z serwera do aplikacji miała nie wiecej niż te 100tysięcy wierszy?

data zawarta w rekordach jest typu double (zmodyfikowana data julianska MJD).

jesli ktoś bawił się z takim czymś to chetnie usłyszę którędy droga smile.gif

pozdrawiam

Ten post edytował ky3orr 29.03.2009, 01:56:47


--------------------
yegomość KY3ORR
Go to the top of the page
+Quote Post
erix
post 30.03.2009, 09:32:15
Post #2





Grupa: Moderatorzy
Postów: 15 467
Pomógł: 1451
Dołączył: 25.04.2005
Skąd: Szczebrzeszyn/Rzeszów




Cytat
Danych za ten okres moze byc kilka, a może być 100milionów.

Może where na resztę z dzielenia przez jakis warunek?

Cytat
tak, żeby tabela końcowa wracająca z serwera do aplikacji miała nie wiecej niż te 100tysięcy wierszy?

No to pozostaje chyba generowanie liczb losowych w zależności od liczby; order by rand() jest zbyt czasochłonne.


--------------------

ZCE :: Pisząc PW załączaj LINK DO TEMATU i TYLKO w sprawach moderacji :: jakiś błąd - a TREŚĆ BŁĘDU? :: nie ponaglaj z odpowiedzią via PW!
Go to the top of the page
+Quote Post
nospor
post 30.03.2009, 09:43:01
Post #3





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




najpierw zliczasz ile masz wszystkich wierszy (zwykly select count(*))
jesli malo, to generujesz zapytanie co pobiera wszystkie
jesli duzo to generujesz zapytanie co pobiera co n-ty. tu masz przyklad na takie zapytanie:
http://nospor.pl/mysql-faq-n25.html#faq-7


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post
maly_swd
post 30.03.2009, 14:17:30
Post #4





Grupa: Zarejestrowani
Postów: 744
Pomógł: 118
Dołączył: 14.02.2009
Skąd: poziome

Ostrzeżenie: (0%)
-----


nospor->Malo optymalnie:

wystarczy zwykle zapytanie select * from stats order by date
sprawdzenie ile zwrocilo rekordow: mysql_num_rows($uchwyt_do_zapytania)

pozniej sprawdzasz if($ilosc_rekordow>100000) $step=round($iloscrekordow/100000); else $step=1;

i na koniec w while($dane=mysq_fetch_array( $uchwyt_do_zapytania)){

mysql_data_seek($uchwyt_do_zapytania, $pozycja+$step);
$pozycja=$pozycja+$step;

}

* to jest tylko szkic logiczny ale przedstawia co trzeba uzyc i jak


--------------------
śmieszne obrazki
Kryzys: Ser jem spleśniały, wino piję stare i samochód mam bez dachu..
Go to the top of the page
+Quote Post
erix
post 30.03.2009, 17:59:37
Post #5





Grupa: Moderatorzy
Postów: 15 467
Pomógł: 1451
Dołączył: 25.04.2005
Skąd: Szczebrzeszyn/Rzeszów




~maly_swd, niby czemu? Twój przykład zeżre dużo więcej zasobów (przede wszystkim pamięci) niż ~nospora.


--------------------

ZCE :: Pisząc PW załączaj LINK DO TEMATU i TYLKO w sprawach moderacji :: jakiś błąd - a TREŚĆ BŁĘDU? :: nie ponaglaj z odpowiedzią via PW!
Go to the top of the page
+Quote Post
nospor
post 30.03.2009, 19:15:00
Post #6





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




Cytat
nospor->Malo optymalnie:
yyy, opierasz swoją teorie na doswiadczeniach? To szybko lec i poprawiaj kody, które do tej pory napisales smile.gif


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post
piotrooo89
post 30.03.2009, 19:17:28
Post #7


Newsman


Grupa: Moderatorzy
Postów: 4 005
Pomógł: 548
Dołączył: 7.04.2008
Skąd: Trzebinia/Kraków




~maly_swd stworzyłeś jakiegoś potworka pamięciożernego. nie ma nic lepszego od przerzucenia liczenia na serwer SQL.


--------------------
Go to the top of the page
+Quote Post
ky3orr
post 30.03.2009, 22:12:17
Post #8





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 25.10.2004
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


nospor dzięki za linka.
teraz muszę rozkminić jak to działa, ale jest trop smile.gif

jak sobie poradzę z tematem przedstawię receptę w wątku.

pozdrawiam

Ten post edytował ky3orr 30.03.2009, 22:12:47


--------------------
yegomość KY3ORR
Go to the top of the page
+Quote Post
maly_swd
post 30.03.2009, 23:29:26
Post #9





Grupa: Zarejestrowani
Postów: 744
Pomógł: 118
Dołączył: 14.02.2009
Skąd: poziome

Ostrzeżenie: (0%)
-----


Twoj sposob jest dobry pod warunkiem ze znamy STEP.

*tak moj przyklad jest poparty doswiadczeniem i testami na tabelach po 10-20milionow rekordow


--------------------
śmieszne obrazki
Kryzys: Ser jem spleśniały, wino piję stare i samochód mam bez dachu..
Go to the top of the page
+Quote Post
nospor
post 31.03.2009, 07:47:13
Post #10





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




Cytat
Twoj sposob jest dobry pod warunkiem ze znamy STEP.
No bo przeciez znamy. Jesli masz x rekordow a chcesz sobie wyswietlic z nich tylko y gdzie y < x to wyliczenie step to podstawa matematyki ktorej w podstawowce uczą

Cytat
*tak moj przyklad jest poparty doswiadczeniem i testami na tabelach po 10-20milionow rekordow
blinksmiley.gif
Chcesz policzyc ile rekordow ma baaaardzo duza tabela. Ta bardzo duuuza tabela ma 20mln rekordow i ty w tym celu pobierasz z bazy danych wszystkie 20 mln rekordow..... mistrzu, jestes wielki.... tak samo wielki jak optymalny twoj skrypt winksmiley.jpg

edit:
wykonaj sobie najpierw taki kod
  1. <?php
  2. $sql = 'select * from twojabardzoduzatabela';
  3. $res = mysql_query($sql) or die(mysql_error());
  4. $count = mysql_num_rows($res);
  5. echo $count;
  6. ?>

zmierz ile skrypt zajął pamięci, jak długo sie wykonywał

następnie wykonaj taki kod
  1. <?php
  2. $sql = 'select count(*) from twojabardzoduzatabela';
  3. $res = mysql_query($sql) or die(mysql_error());
  4. $row = mysql_fetch_array($res);
  5. $count = $row[0];
  6. echo $count;
  7. ?>

zmierz ile skrypt zajął pamięci, jak długo sie wykonywał

porównaj uzyskane wyniki ze sobą i przestan wkońcu wypisywac glupoty....

ps: twojabardzoduzatabela to tabela, która ma te pare mln rekordów.


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post
ky3orr
post 31.03.2009, 09:52:17
Post #11





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 25.10.2004
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


nospor czy, aby wykonać ten zestaw poleceń:

Cytat
SET @nr=-1, @coile=5;
select * from (
select @nr:=@nr+1 _nr,tabela.* from tabela
) jakisalias where _nr % @coile = 0;

trzeba zamknąć je w jakąś procedurę czy funkcję?

próbowałem przetestować to w SQL Query Browserze z pakietu MySQL GUI Tools i klumna która powinna być numerowana zwróciła mi NULLe.
podejżewam, że linia z setem i zapytanie wykonały sie niezależnie...

pozdrawiam

Ten post edytował ky3orr 31.03.2009, 09:53:04


--------------------
yegomość KY3ORR
Go to the top of the page
+Quote Post
nospor
post 31.03.2009, 09:59:53
Post #12





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




SET to jedno zapytanie
kolejne linie to następne jedno zapytanie. One powinny byc wykonane jedno po drugim.
W php bedą to poprostu dwa mysql_query() po sobie.

Nie wiem jak to realizuje twoj SQL Query Browser
Przykladowo sqlyog ktorego uzywam ma opcje wykonywania zapytan jako calosci i dziala ok.


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post
dr_bonzo
post 31.03.2009, 10:23:32
Post #13





Grupa: Przyjaciele php.pl
Postów: 5 724
Pomógł: 259
Dołączył: 13.04.2004
Skąd: N/A

Ostrzeżenie: (0%)
-----


@ky3orr: Query Browser pod tym wzgledem to gowno, nie potrafi wykonac kilku SQLek oddzielonych srednikiem, wiec musisz wrzucac zapytania (dwa) pojedynczo do JEDNEGO taba.
Uzyj phpMyAdmin - tam takie cos dziala - wrzuc wszystkie zapytania od razu.


--------------------
Nie lubię jednorożców.
Go to the top of the page
+Quote Post
maly_swd
post 31.03.2009, 15:25:30
Post #14





Grupa: Zarejestrowani
Postów: 744
Pomógł: 118
Dołączył: 14.02.2009
Skąd: poziome

Ostrzeżenie: (0%)
-----


nospor-> widze ze nie zrozumiales tego co napisalem (szkoda). Jest tam napisane ze jest to szkic. W przypadku jak nie znamy ile baza ma rekordow (nie wykonujemy wczesniej select count(*)...

tylko mamy np select id, text, pole from tabela where pole='cos' (bo takie wyniki chcemy dostac) i wyciagnac z tego 120 rekordow (nie piwrwszych - tylko z STEP x)

Takie zapytanie wykona sie szybko i nie pobierasz wszystkich rekordow do PHP. Druga sprawa ze taki wynik jest cachowany przez mysqla.


--------------------
śmieszne obrazki
Kryzys: Ser jem spleśniały, wino piję stare i samochód mam bez dachu..
Go to the top of the page
+Quote Post
erix
post 31.03.2009, 18:42:49
Post #15





Grupa: Moderatorzy
Postów: 15 467
Pomógł: 1451
Dołączył: 25.04.2005
Skąd: Szczebrzeszyn/Rzeszów




Cytat
Druga sprawa ze taki wynik jest cachowany przez mysqla.

No właśnie. CAŁY WYNIK, a nie tylko liczba rekordów. Poza tym, wykonanie dodatkowego zapytania nieraz się bardziej opłaca.

A jeśli już chcesz na upartego liczyć wyciągnięte:
Cytat
sprawdzenie ile zwrocilo rekordow: mysql_num_rows($uchwyt_do_zapytania)

Użycie tej funkcji jest odradzane, poczytaj trochę, to porozmawiamy. Jeśli już chcesz tak liczyć rekordy, to poszukaj o SQL_CALC_FOUND_ROWS.


--------------------

ZCE :: Pisząc PW załączaj LINK DO TEMATU i TYLKO w sprawach moderacji :: jakiś błąd - a TREŚĆ BŁĘDU? :: nie ponaglaj z odpowiedzią via PW!
Go to the top of the page
+Quote Post
nospor
post 31.03.2009, 20:09:00
Post #16





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




Cytat
nospor-> widze ze nie zrozumiales tego co napisalem (szkoda).

No sorki, ale napisales dosc wyraźnie:
Cytat
wystarczy zwykle zapytanie select * from stats order by date
sprawdzenie ile zwrocilo rekordow: mysql_num_rows($uchwyt_do_zapytania)
Inaczej tego raczej rozumiec nie mozna smile.gif
Cytat
pozniej sprawdzasz if($ilosc_rekordow>100000) $step=round($iloscrekordow/100000); else $step=1;

i na koniec w while($dane=mysq_fetch_array( $uchwyt_do_zapytania)){

mysql_data_seek($uchwyt_do_zapytania, $pozycja+$step);
$pozycja=$pozycja+$step;

Przeciez ty wtym przykladzie ewidentnie pobierasz z mysql wszystkie 20mln rekordow a dopiero potem stepem w php pobierasz tylko co ktorys.
Zorientowales sie dopiero teraz ze sie myliles i starasz sie odwrocic kota ogonem choc i to ci nie wychodzi.

weź wykonaj te dwa przyklady co ci podalem pare postow wczesniej to moze wkoncu do ciebie dotrze w jak wielkim bledzie jestes
Jesli tego nie zrobisz, dalsza dyskusja wydaje sie raczej zbedna

Cytat
i wyciagnac z tego 120 rekordow
zauwaz ze my tu mowimy o tabeli ktora ma liczbę rekordow liczoną w milionach i chcemy z tego wyciągnac 100tys a nie nedzne 120 rekordów


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post
ky3orr
post 31.03.2009, 20:47:51
Post #17





Grupa: Zarejestrowani
Postów: 28
Pomógł: 0
Dołączył: 25.10.2004
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


Koledzy!

nie było moją intencją skłócić kogokolwiek zakładając tgen temat, jednak czytając cały topic wiele można sobie uświadomić o istocie pamięciożerności przez tgen czy tantan styl zapytań.

Puki co staram się ujarzmić kilka zapytań jednocześnie smile.gif

pozdrawiam


--------------------
yegomość KY3ORR
Go to the top of the page
+Quote Post
rzymek01
post 31.03.2009, 21:42:01
Post #18





Grupa: Zarejestrowani
Postów: 592
Pomógł: 62
Dołączył: 3.08.2006

Ostrzeżenie: (0%)
-----


maly_swd, a czy czasem mysql_num_rows nie przelatuje wszystkiego jeszcze raz? biggrin.gif


--------------------
:]
Go to the top of the page
+Quote Post
nospor
post 31.03.2009, 22:00:12
Post #19





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




Cytat
Puki co staram się ujarzmić kilka zapytań jednocześnie

Z racji, ze przeprowadzilem sobie wewnetrzny test, to masz juz gotowy kod:
  1. <?php
  2. $time1 = microtime(true);
  3. $sql = 'select count(*) from city_city';
  4. $res = mysql_query($sql) or die(mysql_error());
  5. $row = mysql_fetch_array($res);
  6. $count = $row[0];
  7.  
  8. $coIle = round($count/100000);
  9. echo 'Ilosc wszystkich rekordow:'.$count;
  10. echo '<br />Co ile:'.$coIle;
  11. mysql_query('SET @nr=-1, @coile='.$coIle);
  12. $res = mysql_query('select *
  13. from (select
  14.        @nr:=@nr+1    _nr,
  15.        city_city.*
  16.      from city_city) jakisalias
  17. where _nr % @coile = 0') or die(mysql_error());
  18. $i=0;
  19. while ($row = mysql_fetch_array($res)){
  20. //tu cos sobie rob z rekordem
  21. $i++;
  22. }
  23. echo '<br />Ilosc przetworzonych rekordow:'.$i;
  24. echo '<br />Czas '.(microtime(true) - $time1);
  25. ?>

A oto wynik:
Ilosc wszystkich rekordow:6359961
Co ile:64
Ilosc przetworzonych rekordow:99375
Czas 7.34749293327

A tutaj kod w wersji maly_swd:
  1. <?php
  2. $time1 = microtime(true);
  3. $res = mysql_query('select * from city_city') or die(mysql_error());
  4. $count = mysql_num_rows($res);
  5. $coIle = round($count/100000);
  6. echo 'Ilosc wszystkich rekordow:'.$count;
  7. echo '<br />Co ile:'.$coIle;
  8.  
  9. $poz = 0;
  10. $i=0;
  11. while ($row = mysql_fetch_array($res)){
  12. $poz+=$coIle;
  13. if (!mysql_data_seek($res,$poz)) break;
  14. $i++;
  15. }
  16.  
  17. echo '<br />Ilosc przetworzonych rekordow:'.$i;
  18. echo '<br />Czas '.(microtime(true) - $time1);
  19. ?>

I wynik:
Ilosc wszystkich rekordow:6359961
Co ile:64
Fatal error: Maximum execution time of 990 seconds exceeded


Jak widac tabela ma ponad 6 mln rekordow.

Dla mojej wersji skrypt wykonywał sie 7 sekund. Procesy systemowe w normie, podkoczyl jedynie troche proces mysql ale nie zuzywal wcale wiecej pamieci niz normalnie.

Dla wersji malego skrypt wykonywal sie koszmarnie dlugo. Proces apachea wskoczyl mi na maxa i zajął ponad 300MB pamieci.
Dodatkowo nie doczekalem sie na wynik. Musialem sztucznie zwiększyc $coIle na 20000 by doczekac sie wyniku. Oto on:
Ilosc wszystkich rekordow:6359961
Co ile:20000
Ilosc przetworzonych rekordow:317
Czas 20.1107699871

PRzykladowo moj skrypt dla tej wartosci $coIle uzyskal nastepujace wyniki
Ilosc wszystkich rekordow:6359961
Co ile:20000
Ilosc przetworzonych rekordow:318
Czas 7.14381098747


Wnioski: no chyba nie musze mowic.... smile.gif

@maly_swd jesli naprawde myslales o innym rozwiązaniu to prosze podaj je dokladnie. Jesli jednak nie, to moze wkoncu przyjmiesz fakty do wiadomosci.

edit:
a, i jeszcze wyniki moich wczesniej podanych skryptow dla tej samej tabeli z 6 mln rekordow

czas dla select count(*): 0.00517010688782
czas dla mysql_num_rows: 6.46986794472

no comments.... winksmiley.jpg


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post
piotrooo89
post 31.03.2009, 22:01:57
Post #20


Newsman


Grupa: Moderatorzy
Postów: 4 005
Pomógł: 548
Dołączył: 7.04.2008
Skąd: Trzebinia/Kraków




robiąć tak jak napisał ~maly_swd można w piękny sposób zajechać PHP. i nawet przy tych nędznych 120 rekordach będzie widoczna różnica. jak że sprawa wymaga testów przeprowadziłem takowe, wyniki:

  1. <?php
  2. include ('mysql.inc');
  3. $sql = 'select * from termin';
  4. $res = mysql_query($sql) or die(mysql_error());
  5. $count = mysql_num_rows($res);
  6. $czas1 = microtime();
  7. echo $czas1;
  8. echo '</br>';
  9.  
  10. $sql1 = 'select count(*) from termin';
  11. $res1 = mysql_query($sql1) or die(mysql_error());
  12. $row1 = mysql_fetch_array($res1);
  13. $count1 = $row1[0];
  14. $czas2 = microtime();
  15. echo $czas2;
  16. echo '</br>';
  17. echo $czas2-$czas1;
  18. ?>


i wyniki:

Kod
0.56250300 1238533233
0.56390500 1238533233
0.001402


testowane na 222 rekordach przy 100 tyś będzie proporcjonalnie więcej...


--------------------
Go to the top of the page
+Quote Post

2 Stron V   1 2 >
Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 14.08.2025 - 00:22