Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Bardzo mała szybkość zapytań do SQL
JohnyBB
post
Post #1





Grupa: Zarejestrowani
Postów: 5
Pomógł: 0
Dołączył: 16.05.2008

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


Witam.
Jestem w miarę początkującym i doszedłem do problemu z którym nie mogę sobie poradzić, mianowicie:
jest sobie baza danych SQL, jest skrypt PHP który ma za zadanie wczytanie danych z pliku XML.
Plik XML - dość duży - około 16 tys pozycji.
Skrypt 'leci' po kolei i wczytuje dane z pliku, jeśli tylko wyświetlam te dane to trwa to moment- natomiast gdy robię UPDATE do bazy trwa to bardzo długo i wysypuje się po pewnym czasie.
Prawdopodobnie mam gdzieś błąd który zwalnia całą procedurkę - czy mogę prosić o pomoc forumowiczów ?


CODE

$data = simplexml_load_file(file.xml');


foreach($data -> produkty as $produkty)
{
foreach($produkty -> produkt as $produkt)
{

$id = (string) $produkt['id'];
$cena_netto = (string) $produkt['cena_netto'];
$dostepny = (string) $produkt['dostepny'];


if ($dostepny>0)
{

$query = "
UPDATE produkt SET wyswietlony=1,cena_netto='$cena_netto' WHERE kod_producenta LIKE '$id'
";
$result = mysql_query($query)
or die("Query UPDATE is failed");
}


}
}


Ten post edytował JohnyBB 16.05.2008, 13:52:09
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 16)
kszychu
post
Post #2





Grupa: Przyjaciele php.pl
Postów: 2 712
Pomógł: 23
Dołączył: 27.10.2003
Skąd: z kontowni

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


Proszę poprawić bbcode.
Go to the top of the page
+Quote Post
batman
post
Post #3





Grupa: Moderatorzy
Postów: 2 921
Pomógł: 269
Dołączył: 11.08.2005
Skąd: 127.0.0.1




No cóż. Skoro masz 16 tyś. pozycji to nie ma co się dziwić, że wolno działa, zwłaszcza, że update jest robiony dla większości produktów. Można nieco poprawić wydajność zapytania, jednak i tak nic to nie pomoże, jeśli uruchamiasz skrypt w przeglądarce. Masz dwa wyjścia:
1. Podzielić plik na mniejsze paczki i każdą paczkę z osobna mielić (samo dzielenie pliku może się nie udać z powodu dużego rozmiaru pliku).
2. Uruchomić skrypt w konsoli.
Go to the top of the page
+Quote Post
kitol
post
Post #4





Grupa: Zarejestrowani
Postów: 162
Pomógł: 26
Dołączył: 19.01.2007

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


Wg mnie. wykonywanie 16tys razy mysql_query jest nieoptymalne. Z doświadczenia wiem, że lepiej jest zrobić konwersje pliku XML do formatu csv (lub innego rozdzielonego dowolnymi znakami). Oczywiście za pomocą PHP w pętli (szybkość będzie taka jak przy wyświetlaniu). Następnie wywołanie w mysql LOAD DATA INFILE nazwa_pliku..... która załaduje dane do bazy.

LIKE jest niezbędne? Nie można użyć = (IMG:http://forum.php.pl/style_emoticons/default/questionmark.gif)
Przy każdym zapytaniu modyfikujesz tylko jeden czy więcej wierszy w tabeli?
Go to the top of the page
+Quote Post
zimi
post
Post #5





Grupa: Zarejestrowani
Postów: 233
Pomógł: 9
Dołączył: 3.06.2007

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


jeśli jesteś baaaardzo początkujący to może musisz zrobić klucz na `kod_producenta` (IMG:http://forum.php.pl/style_emoticons/default/smile.gif)
aczkolwiek z prostego rachunku wynika że jeśli zrobisz 16000 update'ów z którego każdy dajmy na to zajmuje 10 ms, co jest chyba dość realne, to mamy 3 min... w sumie nie napisałeś co znaczy bardzo długo..., nie napisałeś też co i jak się wysypuję...

BTW. LIKE który nie wykorzystuję żadnych "znaczków dowolności", jest chyba równoważny =... zdaję się że tak kiedyś wyczytałem... ale mogę się mylić...
Go to the top of the page
+Quote Post
JohnyBB
post
Post #6





Grupa: Zarejestrowani
Postów: 5
Pomógł: 0
Dołączył: 16.05.2008

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


Przy każdym zapytaniu modyfikuję tylko jeden wiersz w tabeli.
Sęk w tym że ta baza instnieje i nie mogę jej zmieniać - więc zmiana klucza odpada.
Bardzo długo znaczy - około godziny. Wysypuje się w taki sposób, ze wyświetla się "nie można odnaleźć strony itd." nie pojawia się zatem żaden Error - pewnie jest przekroczony czas jakiś.
LIKE nie jest niezbędne - takie znalazłem rozwiązanie - czyli zamieniam na =
---
Cytat
1. Podzielić plik na mniejsze paczki i każdą paczkę z osobna mielić (samo dzielenie pliku może się nie udać z powodu dużego rozmiaru pliku).
2. Uruchomić skrypt w konsoli.

ad1 - odpada - nie ma na to czasu bawić się z krojeniem xml'a 1 dziennie.
ad2 - można jaśniej ? jak uruchomić skrypt w konsoli ?
Cytat
Wg mnie. wykonywanie 16tys razy mysql_query jest nieoptymalne. Z doświadczenia wiem, że lepiej jest zrobić konwersje pliku XML do formatu csv (lub innego rozdzielonego dowolnymi znakami). Oczywiście za pomocą PHP w pętli (szybkość będzie taka jak przy wyświetlaniu). Następnie wywołanie w mysql LOAD DATA INFILE nazwa_pliku..... która załaduje dane do bazy.


czyli LOAD DATA INFILE wykonuję z MyAdmina ? po uprzedniej zamianie XML na inny format ?
Go to the top of the page
+Quote Post
kitol
post
Post #7





Grupa: Zarejestrowani
Postów: 162
Pomógł: 26
Dołączył: 19.01.2007

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


Możesz robić wszystko ręcznie i wówczas LOAD DATA wykonujesz z MyAdmina. Wygodniej jest to umieścić na końcu skryptu który dokonuje konwersji na CSV. Musisz mieć ustawiony klucz unikalny oraz dodać parametr REPLACE do LOAD DATA jeżeli chcesz UPDATEować dane, w przeciwnym razie dane zostaną dopisane do tabeli. Więcej o load data możesz przeczytać tu
Modyfikacje kluczy możesz wykonywać na działającej bazie- z tym nie ma problemu.
Go to the top of the page
+Quote Post
Kocurro
post
Post #8





Grupa: Zarejestrowani
Postów: 461
Pomógł: 32
Dołączył: 17.09.2003
Skąd: Łódź

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


Po primo - używasz mało wydajnej metody by odczytywać XML'a.

Po sekundo zamiast LIKE daj = .

Po tertio - jeśli robisz update to nie wywalaj bez tranzakcji w przypadku błędu bo integralności danych się sypie.

Po quatro - PHP wykłada się na alokacji pamięci w tym wypadku. Stwórz własny parser xml (patrz funkcja xml_parse czy jakoś tak), wywal niepotrzebne pętla.

Po quinto - jeśli możesz użyj prepared statements

Po .... - nie stosuj konstrukcji w PHP'ie " $zmienna " - przy takiej ilości danych faktycznie może to trochę obciążać

Po .... - powiedz jaka baza danych i (jeśli to ma znaczenie) jaki typ tabel a porawdzę więcej

Po .... - dodaj klucze

Po .... - zależnie od bazy danych możesz być zmuszony po tak ostrej zmianie danych dokonać analizy danych by odnowić klucze

Po .... - dlaczego cena netto jest ciągiem znaków a nie liczbą decimal ? to jest niepotrzebne obciążanie bazy danych (czyt. źle zaprojektowana baza )

pozdr.
Łukasz (IMG:http://forum.php.pl/style_emoticons/default/smile.gif)
Go to the top of the page
+Quote Post
JohnyBB
post
Post #9





Grupa: Zarejestrowani
Postów: 5
Pomógł: 0
Dołączył: 16.05.2008

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


Cytat(kitol @ 17.05.2008, 08:48:45 ) *
Możesz robić wszystko ręcznie i wówczas LOAD DATA wykonujesz z MyAdmina. Wygodniej jest to umieścić na końcu skryptu który dokonuje konwersji na CSV. Musisz mieć ustawiony klucz unikalny oraz dodać parametr REPLACE do LOAD DATA jeżeli chcesz UPDATEować dane, w przeciwnym razie dane zostaną dopisane do tabeli. Więcej o load data możesz przeczytać tu
Modyfikacje kluczy możesz wykonywać na działającej bazie- z tym nie ma problemu.

kurcze chyba w to się nie zagłębię - finalnie ma być to automatycznie uruchamiane przez usera... więc odpadają takie operacje...
Kocurro:
ad 1 - chodzi Ci o : simplexml_load_file ? to mało wydajne ?
ad 2 - wstawiłem =
zamieniłem stringi , tzn usunąłem te przekształcenia i zadziałało - jednak długo to trwa a problem jest ciekawy...
Jak pisałem jestem noobem więc - dodaj klucze ? rozumiem ze do tabel ale w przypadku gdy jest źle zaprojektowana baza musiałbym całą zaprojektować od nowa a co za tym idzie przepisać cały kod - nie ma na to czasu niestety.
Cytat
powiedz jaka baza danych
tzn jaka ? postgres mysql ? chodzi Ci o serwer?
Cytat
nie stosuj konstrukcji w PHP'ie " $zmienna "
w jaki sposób mam to zastąpić ?
Pozdrawiam
Go to the top of the page
+Quote Post
Shili
post
Post #10





Grupa: Zarejestrowani
Postów: 1 085
Pomógł: 231
Dołączył: 12.05.2008

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


Cytat
w jaki sposób mam to zastąpić ?
Z tego co rozumiem, to po prostu wpisz $zmienna, bez cudzysłowa. Cudzysłów jest dodatkowo parsowany w poszukiwaniu na przykład zmiennych, więc siłą rzeczy jego wykonanie trwa dłużej. Zamiast tego łącz łańcuchy.

Ten post edytował Shili 17.05.2008, 14:02:53
Go to the top of the page
+Quote Post
em1X
post
Post #11





Grupa: Zarejestrowani
Postów: 984
Pomógł: 41
Dołączył: 16.03.2002
Skąd: Płock

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


Lepiej pokaż strukturę Twojej tabeli. Źle zaprojektowana tabela znacznie spowalnia na niej działanie, a już nie raz widziałem takie perełki, że trzymano liczby 0 lub 1 (boolean) w polach typu bigint(1).
Go to the top of the page
+Quote Post
Kicok
post
Post #12





Grupa: Zarejestrowani
Postów: 1 033
Pomógł: 125
Dołączył: 17.09.2005
Skąd: Żywiec

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


Oprócz powyższych porad spróbuj jeszcze zrobić coś takiego:

- Zdejmij wszystkie klucze/indeksy które nie są niezbędne przy tej operacji (kurs SQL -> ALTER TABLE )
- Zrób te 16 tyś. UPDATE
- Ponakładaj klucze/indeksy z powrotem
- Wykonaj REPAIR TABLE


Natomiast w manualu MySQL znalazłem coś takiego:
Cytat
If you use ALTER TABLE on a MyISAM table, all non-unique indexes are created in a separate batch (as for REPAIR TABLE). This should make ALTER TABLE much faster when you have many indexes.

This feature can be activated explicitly for a MyISAM table. ALTER TABLE ... DISABLE KEYS tells MySQL to stop updating non-unique indexes. ALTER TABLE ... ENABLE KEYS then should be used to re-create missing indexes. MySQL does this with a special algorithm that is much faster than inserting keys one by one, so disabling keys before performing bulk insert operations should give a considerable speedup. Using ALTER TABLE ... DISABLE KEYS requires the INDEX privilege in addition to the privileges mentioned earlier.
Go to the top of the page
+Quote Post
batman
post
Post #13





Grupa: Moderatorzy
Postów: 2 921
Pomógł: 269
Dołączył: 11.08.2005
Skąd: 127.0.0.1




Cytat
ad2 - można jaśniej ? jak uruchomić skrypt w konsoli ?

Uruchomienie skryptu w konsoli oznacza, że uruchamiasz terminal (konsolę), następnie przechodzisz do odpowiedniego katalogu (polecenie cd), a następnie uruchamiasz skrypt
Kod
php ./twoj_skrypt.php
Nie wiem jak to się robi pod windą (IMG:http://forum.php.pl/style_emoticons/default/winksmiley.jpg) ale domyślam się, że podobnie.
Go to the top of the page
+Quote Post
JohnyBB
post
Post #14





Grupa: Zarejestrowani
Postów: 5
Pomógł: 0
Dołączył: 16.05.2008

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


batman: to jest na virtualnym serwerze - więc na konsolę się nie załaduję - nie mam konta na shell'u.

kicok: klucze w tabeli czy w całej bazie ?

em1x: pomimo, ze baza jest fatalnie zaprojektowana, strukturę już wcześniej poprawiłem więc nie ma takich kruczków.
Go to the top of the page
+Quote Post
em1X
post
Post #15





Grupa: Zarejestrowani
Postów: 984
Pomógł: 41
Dołączył: 16.03.2002
Skąd: Płock

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


Cytat(JohnyBB @ 19.05.2008, 07:41:55 ) *
em1x: pomimo, ze baza jest fatalnie zaprojektowana, strukturę już wcześniej poprawiłem więc nie ma takich kruczków.


więc czemu jej nie pokażesz? przecież to żadna tajemnica.. no chyba, że się wstydzisz (IMG:http://forum.php.pl/style_emoticons/default/aaevil.gif)
Go to the top of the page
+Quote Post
yivan
post
Post #16





Grupa: Zarejestrowani
Postów: 20
Pomógł: 0
Dołączył: 9.08.2005
Skąd: Zamość

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


Z tego wszystkiego najwolniej działa mysql_query(). Spróbuj najpierw przepisać dane, które wymagają zaktualizowania do jednej długiej tablicy. Potem daj unset($data) jeśli te dane nie są Ci już potrzebne. Następnie iterując tablicę z danymi utwórz dłuuuugie zawierające jednocześnie ok 1000 instrukcji Update, ew co 1000 wierszy rób mysql_query().

Wszystko po to abyś nie robił do 16tyś mysql_query ale maks kilkanaście, tak będzie szybciej.
Go to the top of the page
+Quote Post
JohnyBB
post
Post #17





Grupa: Zarejestrowani
Postów: 5
Pomógł: 0
Dołączył: 16.05.2008

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


em1x: nie chcę pokazywać bazy - powiedzmy że się wstydzę, choć nie ja ją projektowałem.

yivan - ok - domyslam się że to opóźnia, bo ciągle nawiązuje połączenie aby 1 update wykonać i zamyka. spróbuję Twojej metody.

OK - pytanie - jak zadać kilka UPDATE w jednym mysql_query ? Jakieś błędy mi powychodziły przy testach.
Go to the top of the page
+Quote Post

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

 



RSS Aktualny czas: 24.08.2025 - 11:05