![]() |
![]() |
![]()
Post
#1
|
|
Grupa: Zarejestrowani Postów: 54 Pomógł: 0 Dołączył: 9.09.2003 Skąd: Bełchatów Ostrzeżenie: (0%) ![]() ![]() |
Witam,
mam problem z prędkością wykonywania zapytania. Cron uruchamia skrypt codziennie i jeżeli zajdą pewne warunki to przepisuje wartości z jednej kolumny do drugiej. W tabeli jest póki co ok. 37 tyś rekordów. Problem w tym, że przepisywanie trwa bardzo długo, tj. tylko 2tyś rekordów na minutę. Wydawało mi się, że taka nieskomplikowana rzecz powinna trwać parę sekund. Na początku myślałem, że to wina pythona, dlatego przepisałem to na php, ale wciąż to samo. Sam kod do przepisywania wygląda tak:
Całość wykonuje się na serwerach home.pl, więc nie powinno być dużych opóźnień. Co o tym sądzicie? Da się to jakoś przyspieszyć, czy taka "prędkość" to norma? Edit: Zmieniłem warunek po którym edytujemy wpisy z name na uid i... idzie o niebo szybciej. Taki głupi błąd :/ Ten post edytował Radek_1 1.09.2011, 20:32:16 |
|
|
![]() |
![]()
Post
#2
|
|
Grupa: Zarejestrowani Postów: 14 Pomógł: 5 Dołączył: 27.08.2009 Ostrzeżenie: (0%) ![]() ![]() |
W ten sposob skrypt zawsze bedzie dzialal wolno.
Zobacz co robisz: 1. Pobierasz w pesymistycznym przypadku 37 tys. rekordow 2. Iterujesz po rekordach i wykonujesz X zapytan update do bazy (kazde jest kosztowne ze wzgledu na uzyte mechanizmy blokowania w zaleznosci od silnika) Lepiej bys zrobil, jakbys wykonal jedno zapytanie update do bazy, bez zadnego pobierania rekordow i iterowania po nich. Poszukaj na googlach informacji na temat update from select P.S. Przesiadlem sie na postgresa i nie wiem, czy MySQL obsluguje juz mozliwosc uzycia tej samej tabeli w subquery update'a, ale na to tez sa sposoby |
|
|
![]()
Post
#3
|
|
Grupa: Zarejestrowani Postów: 744 Pomógł: 118 Dołączył: 14.02.2009 Skąd: poziome Ostrzeżenie: (0%) ![]() ![]() |
|
|
|
![]()
Post
#4
|
|
Grupa: Zarejestrowani Postów: 54 Pomógł: 0 Dołączył: 9.09.2003 Skąd: Bełchatów Ostrzeżenie: (0%) ![]() ![]() |
Dziękuję bardzo za pomoc, dużo szybciej chodzi. W zasadzie sam powinienem na to wpaść, taki banał się teraz to wydaje, jak napisaliście swoje rozwiązania... (IMG:style_emoticons/default/wstydnis.gif)
To kolejne pytanko, o sam skrypt. Skrypt jest w pythonie, przerobiłem go, aby wstawić na forum na php, ale sądzę, że to jest sprawą drugorzędną. Pobiera dane ze strony, następnie sprawdza czy użytkownik (zmienna $name_p) istnieje. Jeżeli nie dodaje go do bazy danych. Jeżeli istnieje to dodaje do jego czasu w aktualnym dniu i miesiącu 15 minut.
Pytanie, czy da się to jakoś przyspieszyć? Docelowo ma być ponad pół mln rekordów i chciałbym, żeby to wykonywało się jak najszybciej. Wąskim gardłem wg. mnie jest tutaj zapytanko pobierające danego użytkownika. Inne rozwiązanie:
Takie coś nie ma sensu, bo mysql_query zwraca 1 jeżeli wykona się zapytanie, albo 0 jeżeli nie. Jeżeli użytkownik nie istnieje to i tak zwróci 1, bo pytanie się wykona, ale nie zaktualizuje żadnego rekordu, bo rekord o podanych warunkach nie istnieje. Jakieś sugestie? Edit: Znalazłem funkcje mysql_affected_rows() ale czy ona działa szybciej niż sposób przedstawiony na początku postu - śmiem wątpić. Ten post edytował Radek_1 2.09.2011, 22:48:05 |
|
|
![]()
Post
#5
|
|
Grupa: Zarejestrowani Postów: 2 178 Pomógł: 596 Dołączył: 25.09.2009 Skąd: Piwniczna-Zdrój Ostrzeżenie: (0%) ![]() ![]() |
Chyba niepotrzebnie w tabeli time_online zapisujesz nazwy użytkowników, bo masz tam już ich id (kolumna UID). Jeśli jednak tak ma być, to nałóż indeks zarówno na UID, jak i na name (zauważ, że wartości w tych kolumnach powinny być unikalne).
Do sprawdzenia ilości rekordów pobranych przez zapytanie SQL (SELECT lub SHOW) możesz użyć mysql_num_rows(), jednak funkcja ta jest wolniejsza aniżeli wykonanie zapytania zliczającego i wyekstrahowanie liczby z wyniku tego zapytania. mysql_affected_rows() pobiera liczbę rekordów przetworzonych (INSERT, UPDATE, REPLACE lub DELETE) przez zapytanie SQL i jest to jedyny sposób, aby liczbę tych przetworzonych rekordów pobrać. W sumie to pierwsze zapytanie możesz pominąć:
Całość wygląda na obsługę statusu online użytkownika, ale nie wiem, po co ten INSERT. |
|
|
![]()
Post
#6
|
|
Grupa: Zarejestrowani Postów: 54 Pomógł: 0 Dołączył: 9.09.2003 Skąd: Bełchatów Ostrzeżenie: (0%) ![]() ![]() |
mortus, zgodnie z tym co napisałem po edytowaniu postu, funkcję mysql_affected_rows znalazłem, jednak jest ona wolniejsza niż sprawdzanie innym zapytaniem czy użytkownik istnieje (sprawdziłem).
Skrypt wyszukuje wszystkich użytkowników na stronie i zlicza ich czas bycia online. Jeżeli użytkownik jest nowy, to dodaje go do czasu "obserwowanych", stąd ten INSERT. |
|
|
![]()
Post
#7
|
|
Grupa: Zarejestrowani Postów: 2 178 Pomógł: 596 Dołączył: 25.09.2009 Skąd: Piwniczna-Zdrój Ostrzeżenie: (0%) ![]() ![]() |
Nie zrozumiałeś mnie, mysql_affected_rows() używamy, aby uzyskać liczbę rekordów zmienionych przez zapytanie z INSERT, UPDATE, REPLACE i DELETE. Inaczej nie możemy tej liczby uzyskać, bo powyższe zapytania nie zwracają żadnych rekordów.
Natomiast mysql_num_rows() możemy użyć, jeśli chcemy uzyskać liczbę rekordów pobranych za pomocą SELECT. Funkcja ta jest jednak wolna.
Akurat Twój skrypt to szczególny przypadek, w którym - jak widzisz - nie ma potrzeby sprawdzania za pomocą SELECT, czy użytkownik w tabeli time_online istnieje, wystarczy bowiem spróbować dokonać aktualizacji rekordu, a jeśli aktualizacja się nie powiedzie (mysql_affected_rows() zwróci 0) to będzie to oznaczać, że użytkownika o nazwie $name_p nie ma w tabeli time_online i trzeba go dodać. Odsyłam do manuala: mysql_num_rows(), mysql_affected_rows(). Cytat Skrypt wyszukuje wszystkich użytkowników na stronie i zlicza ich czas bycia online. Jeżeli użytkownik jest nowy, to dodaje go do czasu "obserwowanych", stąd ten INSERT. Nie zmienia to faktu, że lepiej do wyszukiwania użytkownika nadawałaby się kolumna UID aniżeli name, oraz że obie te kolumny powinny być unikalne i śmiało można nałożyć na nie indeksy, co przyspieszy nieco działanie skryptu. Ten post edytował mortus 4.09.2011, 09:24:59 |
|
|
![]()
Post
#8
|
|
Grupa: Zarejestrowani Postów: 54 Pomógł: 0 Dołączył: 9.09.2003 Skąd: Bełchatów Ostrzeżenie: (0%) ![]() ![]() |
mortus, doskonale rozumiem co napisałeś wcześniej. Powtórzę jeszcze raz, sprawdzanie czy nastąpiła aktualizacja rekordu przy pomocy mysql_affected_rows() jest _wolniejsze_ niż sprawdzenie czy rekord istnieje i późniejsza ewentualna aktualizacja/wstawienie.
Tj. szybciej jest: 1. Sprawdzić czy użytkownik istnieje 2. Zaktualizować jeżeli istnieje 3. Wstawić nowy rekord jeżeli nie istnieje Niż: 1. Zaktualizować rekord 2. Sprawdzić mysql_affected_rows() czy nastąpiła aktualizacja (w przypadku gdy użytkownik nie istnieje to go nie zaktualizuje, no bo jak?) 3. Wstawić nowy rekord jeżeli nie nastąpiła aktualizacja. Cytat Nie zmienia to faktu, że lepiej do wyszukiwania użytkownika nadawałaby się kolumna UID aniżeli name, oraz że obie te kolumny powinny być unikalne i śmiało można nałożyć na nie indeksy, co przyspieszy nieco działanie skryptu. W jaki sposób wyszukiwać po UID? Skoro strona na której sprawdzam czy ktoś jest online jest niezależna ode mnie i napisane są na niej tylko i wyłącznie nazwy? A co do name to nadałem index i jest unikalna (IMG:style_emoticons/default/smile.gif) Ten post edytował Radek_1 4.09.2011, 18:30:15 |
|
|
![]() ![]() |
![]() |
Aktualny czas: 22.08.2025 - 18:07 |