Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [PHP] Efektywne przeszukiwanie dużej tablicy
loocek
post 4.02.2023, 14:25:59
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
trueblue
post 4.02.2023, 14:44:34
Post #2





Grupa: Zarejestrowani
Postów: 6 761
Pomógł: 1822
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 4.02.2023, 16:21:38
Post #3





Grupa: Zarejestrowani
Postów: 338
Pomógł: 70
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 4.02.2023, 21:12:47
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 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 5.02.2023, 13:35:22
Post #5





Grupa: Zarejestrowani
Postów: 6 761
Pomógł: 1822
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 5.02.2023, 15:29:35
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 5.02.2023, 19:07:44
Post #7





Grupa: Zarejestrowani
Postów: 6 761
Pomógł: 1822
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 5.02.2023, 19:18:15
Post #8





Grupa: Zarejestrowani
Postów: 6 365
Pomógł: 1114
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 5.02.2023, 22:34:56
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 6.02.2023, 07:58:34
Post #10





Grupa: Zarejestrowani
Postów: 6 761
Pomógł: 1822
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 6.02.2023, 11:13:08
Post #11





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

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


Ok, ten join śmiga 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. 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 6.02.2023, 11:51:04
Post #12





Grupa: Zarejestrowani
Postów: 6 761
Pomógł: 1822
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
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 28.03.2024 - 15:50