Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> [PHP] Efektywne przeszukiwanie dużej tablicy
loocek
post
Post #1





Grupa: Zarejestrowani
Postów: 20
Pomógł: 0
Dołączył: 18.04.2009

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


Hej,
Mam problem z przeszukaniem dużej tablicy. Tzn. mam w bazie ok 230k rekordów które pobieram do tablicy i następnie przez formularz na stronie pobieram znowu z 10k rekordów do sprawdzenia i teraz muszę zwyczajnie sprawdzić czy te z formularza występują w bazie. No i robiąc to najprościej w pętli czyli sprawdzając każdy z tych 10k czy jest w bazie 230k długo trwa. Sprawdzenie raptem 2k (a nie 10k) zajmuje już 18sek. No a 10k ? a może i 50k chcąc sprawdzić ? przecież to się będzie wykonywało z 1min...2min - bez sensu.

Czy znacie jakiś sposób na jak największe przyspieszenie tego sprawdzania ? Jakiś algorytm albo funkcje ?
pozdrawiam
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 11)
trueblue
post
Post #2





Grupa: Zarejestrowani
Postów: 6 806
Pomógł: 1828
Dołączył: 11.03.2014

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


Jaka to baza? Co masz na myśli pisząc rekord - jedno pole, kilka pól, jakiego typu? Co dokładnie porównujesz? Czy na tabeli są indeksy?
Go to the top of the page
+Quote Post
Salvation
post
Post #3





Grupa: Zarejestrowani
Postów: 406
Pomógł: 73
Dołączył: 15.07.2014

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


Może po prostu przenieś przeszukiwanie na bazę - która ma wbudowane mechanizmy optymalizacyjne - zamiast przeszukiwać to w PHP?
Go to the top of the page
+Quote Post
loocek
post
Post #4





Grupa: Zarejestrowani
Postów: 20
Pomógł: 0
Dołączył: 18.04.2009

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


Jest to MySQL, rekord to mam na myśli jedna z kolumn ze stringami tekstowymi (VARCHAR), tak na tabeli jest indeks.
I muszę sprawdzić czy każdy z tych stringów co ich jest 10k które podaję przez formularz występuje w tej bazie 230k czy nie.


Żle się wyraziłem (IMG:style_emoticons/default/wink.gif)
Rekord to oczywiście jedna z wartości w tej kolumnie VARCHAR ze zwykłymi stringami tekstowymi.
Go to the top of the page
+Quote Post
trueblue
post
Post #5





Grupa: Zarejestrowani
Postów: 6 806
Pomógł: 1828
Dołączył: 11.03.2014

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


Pierwszą metodą jest użycie klauzuli IN. Ale tu ograniczony będziesz zmienną max_allowed_packet (co tu ma związek z długością zapytania).
Drugą metodą, szybszą niż IN w przypadku dużej ilości danych, będzie stworzenie tymczasowej tablicy z indeksem i zapytanie pomiędzy tymi dwiema tablicami.
Go to the top of the page
+Quote Post
loocek
post
Post #6





Grupa: Zarejestrowani
Postów: 20
Pomógł: 0
Dołączył: 18.04.2009

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


Czy możesz rozwinąć choćby tą drugą opcję która ma być szybsza ?
Go to the top of the page
+Quote Post
trueblue
post
Post #7





Grupa: Zarejestrowani
Postów: 6 806
Pomógł: 1828
Dołączył: 11.03.2014

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


1. Tworzysz tymczasową tablicę z polem VARCHAR i indeksem (być może unikalnym) - to możesz zrobić raz, ręcznie.
2. Wstawiasz do niej dane z formularza (INSERT z wieloma wartościami https://www.mysqltutorial.org/mysql-insert-multiple-rows/, ale niekoniecznie wszystkie wartości - patrz: max_allowed_packet).
3. Robisz JOIN
4. Usuwasz dane.
Go to the top of the page
+Quote Post
viking
post
Post #8





Grupa: Zarejestrowani
Postów: 6 381
Pomógł: 1116
Dołączył: 30.08.2006

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


Do takich celów można też przemyśleć silnik memory.
Go to the top of the page
+Quote Post
loocek
post
Post #9





Grupa: Zarejestrowani
Postów: 20
Pomógł: 0
Dołączył: 18.04.2009

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


Na razie ta część MySQL:
Stworzyłem drugą tabelkę lucek_temp do której wrzuciłem 2000 tytułów. I teraz chciałbym uzyskać listę tytułów których nie ma w tej drugiej duzej tabelce. Zatem robię takiego selecta:
select lucek_temp.tytul from lucek_temp join wszystkie ON wszystkie.tytul != lucek_temp.tytul;
i to zapytanie trwa ok 30 sec. po czym proces sam się ubija i wywala mnie z CLI Mysql (bo na raie tam testuję).

Co robię nie tak ?
Go to the top of the page
+Quote Post
trueblue
post
Post #10





Grupa: Zarejestrowani
Postów: 6 806
Pomógł: 1828
Dołączył: 11.03.2014

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


  1. SELECT lt.tytul
  2. FROM lucek_temp AS lt
  3. LEFT JOIN wszystkie AS w ON w.tytul=lt.tytul
  4. WHERE w.tytul IS NULL;

Tym zapytaniem uzyskasz wpisy, których brak we `wszystkie`.

Założyłeś indeks na `tytul` w `lucek_temp`?
Go to the top of the page
+Quote Post
loocek
post
Post #11





Grupa: Zarejestrowani
Postów: 20
Pomógł: 0
Dołączył: 18.04.2009

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


Ok, ten join śmiga (IMG:style_emoticons/default/smile.gif) Tzn zrobiłeś małą literówkę więc powinien wyglądać tak:

  1. SELECT lt.tytul
  2. FROM lucek_temp AS lt
  3. LEFT JOIN wszystkie ON w.tytul=lt.tytul
  4. WHERE w.tytul IS NULL;


I bez indexów (na polach tytul w obu tabelach) zapytanie trwało 23sek. Natomiast po zrobieniu indexów zapytanie trwa... 0 sec. (IMG:style_emoticons/default/smile.gif)
Zatem dorobię sobie jeszcze ten multiinsert rows z formularza PHP do Mysql i wszystko będzie śmigać.

Nie truję już. Dzięki wielkie za pomoc.

Go to the top of the page
+Quote Post
trueblue
post
Post #12





Grupa: Zarejestrowani
Postów: 6 806
Pomógł: 1828
Dołączył: 11.03.2014

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


A w jaki celu robisz to porównanie? Chcesz poinformować użytkownika ile jego danych zostanie dopisanych, etc.?
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: 4.10.2025 - 22:11