Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]Szybkość wykonywania
Forum PHP.pl > Forum > Przedszkole
Warmix
Wykonuję w obrocie pętli wiele przeróżnych operacji. Przy działaniu na powiedzmy 1000 rekordów dość szybko zostaje wszystko przetworzone, problem zaczyna się, gdy tych rekordów mam koło 20000. Całość wykonuje się bardzo wolno.

Chciałbym zapytać, z czego korzystać, by móc przyspieszyć wykonywanie całości.

1. Do łączenia z bazą wykorzystuję mysql. Zapytanie służy tylko do tego, by pozyskać rekordy z bazy, a następnie je usunąć. Czy jeśli wykorzystam mysqli to znacząco te operacje na bazie przyspieszą? Rozumiem, że mysql jest stare i nie powinno się go używać, jednak skrypt został napisany lata temu, gdy nie było jeszcze mysqli dlatego czy warto jest mi go przepisywać? Podkreślam, że nie zależy mi na bezpieczeństwie etc. Tylko i wyłącznie szybkość wykonywania.
Do pozyskania tych danych w pętli używam:

  1. $sql = mysql_query("SELECT * FROM test");
  2. while($wynikb = mysql_fetch_assoc($sql))
  3. {}


Czy mysql_fetch_assoc jest dobrze wydajne? Czy skorzystać z innej funkcji, jak mysql_fetch_row czy w ogóle rzeczywiście skorzystać z mysqli?

2. Do sprawdzenia, czy istnieje konkretny ciąg znaków wykorzystuję preg_match. Czy przy użyciu innej funkcji, jak np. strstr czy strpos proces sprawdzenia danych będzie szybszy?

3. Wykonuję też dzielenie po znaku spacji:
  1. explode(" ", $nazwa);


Czy istnieje inna funkcja, która podzieli mi tak dane i przedstawi w formie tablicy, która jednocześnie będzie szybsza niż explode?

4. Wykorzystuję preg_match_all do wyrażeń regularnych, np.:
  1. preg_match_all('/test\/(.*?) test2 (.*?)$/', $test1, $test2);


Czy jest inna funkcja, która będzie działać podobnie, ale szybciej?



Podkreślam jeszcze raz, że chodzi tylko i wyłącznie o prędkość wykonywania tych operacji, czyli jednocześnie o zmniejszenie zużycia procesora itd. Kwestie bezpieczeństwa, większych możliwości itd. nie są istotne.
Pyton_000
Tak na prawdę nic nie powiedziałeś.

Pokaż lepiej cały kod który robisz w pętli.
Warmix
Daję część kodu. Proszę o jakieś wskazówki dotyczące optymalizacji, żeby to szybciej działało.
Proszę nie zwracać uwagi na jakieś błędy drobne, jak np. pierwszy if (co by było, gdyby nie znalazło ciągu 'gt' - z kody wyciąłem parę rzeczy,które były powtarzalne - dlatego takie jakieś błędy mogą być)



  1. $sql = mysql_query("SELECT * FROM test");
  2. while($wynik = mysql_fetch_assoc($sql))
  3. {
  4.  
  5. $id = $wynik['id'];
  6. $nazwa = $wynik['nazwa'];
  7.  
  8. $dek = $wynik['dek'];
  9. $dek = strtolower($dek);
  10.  
  11. if((preg_match("/gt/",$dek)))
  12. {
  13. $inkl = preg_match_all('/test(.*?)test2(.*?)test3(.*?)$/', $dek, $ffer);
  14. }
  15.  
  16. $sqlb = mysql_query("SELECT * FROM test2");
  17. while($wynikb = mysql_fetch_assoc($sqlb))
  18. {
  19. $nazwa = $wynikb['nazwa'];
  20. $nazwa_s = $wynikb['nazwa_s'];
  21.  
  22. $czesci[0] = $nazwa_s;
  23. $rozmiar_czesci = 0;
  24.  
  25. if(preg_match('/\^/', $nazwa_s))
  26. {
  27. $czesci = explode("^", $nazwa_s);
  28. $rozmiar_czesci = count($czesci)-1;
  29. }
  30.  
  31. for($j = 0; $j <= $rozmiar_czesci; $j++)
  32. {
  33. $nazwa_s = $czesci[$j];
  34. $nazwa_exp = explode(" ", $nazwa_s);
  35. $rozmiar_nazwa_exp = count($nazwa_exp);
  36.  
  37. $spelnia = 0;
  38. for($i=0; $i<=$rozmiar_nazwa_exp-1; $i++)
  39. {
  40. if(preg_match('/'.$nazwa_exp[$i].'/', $ffer[3][0]))
  41. {
  42. $spelnia++;
  43. }
  44. }
  45.  
  46. if($spelnia == $rozmiar_nazwa_exp)
  47. {
  48. if(preg_match('/gt/', $dek))
  49. {
  50. $nadpe = preg_match_all('/test1(.*?)test2(.*?)$/', $ctt, $cate);
  51. $sqla = mysql_query("SELECT * FROM tab1 WHERE tab1='".$id_szab."'");
  52. $wynika = mysql_fetch_assoc($sqla);
  53.  
  54. if(!preg_match('/'.$cate[2][0].'/', $wynika['tab1_dane']))
  55. {
  56. $dane23 = explode("\n", $wynika['tab1_dane']);
  57. $rozmiarek = count($dane23)-2;
  58. if($rozmiarek >= 0)
  59. {
  60. $nadpea = preg_match_all('/test1(.*?)test2(.*?)$/', $dane23[$rozmiarek], $last_2ctt);
  61. $last_ctt = preg_replace('/x(.*?)$/', '', $last_2ctt[2][0]);
  62.  
  63. $dodaj_ten = preg_replace('/x(.*?)$/', '', $cate[2][0]);
  64.  
  65. if($last_ctt == $dodaj_ten)
  66. {
  67. $ctt = $ctt."\n";
  68. }
  69. else
  70. {
  71. $ctt = "\n".$ctt."\n";
  72. }
  73. }
  74. else
  75. {
  76. $ctt = $ctt."\n";
  77. }
  78.  
  79. mysql_query("UPDATE tab1 SET tab1_dane=CONCAT(tab1_dane,'".$ctt."') WHERE tab1='".$id."'");
  80. mysql_query("DELETE FROM dane23i WHERE id='".$id."'");
  81.  
  82. }
  83. }
  84. }
  85. }
  86. }
  87. }
Damonsson
Wrzuć parę (10-20) rekordów z bazy danych, gdzie wpadają w te Twoje wszystkie wyrażenia regularne, ewentualnie opisz czego tam szukasz tymi wyrażeniami. Może jeszcze tam można coś zrobić inaczej.
Pyton_000
Masz zagnieżdżone zapytanie SQL w pętli:
  1. $sqlb = mysql_query("SELECT * FROM test2");

Wyciągnij te dane przed pętlą i zbuduj sobie z niej tablicę raz. Po co za każdym razem to samo odpalać.

  1. if(stripos($dek, 'gt') !== false)

Będzie wydajniejsze od preg_match

  1. $sqla = mysql_query("SELECT * FROM tab1 WHERE tab1='".$id_szab."'");

Jeśli to możliwe wyciągnij wcześniej wszystkie ID i pobierz za jednym zamachem przed pętlami.

  1. mysql_query("UPDATE tab1 SET tab1_dane=CONCAT(tab1_dane,'".$ctt."') WHERE tab1='".$id."'");

To też możesz już po pętlach zrobić przekazując komplet ID
IAmBoskiM
Nie mam pojęcia, jak skonstruowana jest twoja tabela w bazie, ale jeżeli nie będziesz potrzebował wszystkich kolumn z tabeli, to nie używaj * (ALL).
KsaR
Jak wyżej +
Jeśli wielkość liter jest obojętna użyj strpos zamiast stripos, jest szybsze bo nie porównuje wielkości liter.

Poczytaj o PSR żeby łatwiej się czytało twój kod.

count + for bym zamienił na pętlę foreach.

Jak gdzieś modyfikujesz 1 rekord lub kasujesz dodaj na końcu zapytania "LIMIT 1" przez co MySQL nie będzie skanował całej tabeli w poszukiwaniu kolejnych rekordów spełniających warunek.

Inne mniejsze zmiany:
Ogranicz ilość operacji wpływających na procesor, np.
Zamiast:

  1. $dek = $wynik['dek'];
  2. $dek = strtolower($dek);

Zrób:
  1. $dek = strtolower($wynik['dek']);

$ctt = $ctt."\n";
To można skrócić:
$ctt .= "\n";

--
Swoją drogą nowsze rozszerzenie mysqli jest szybsze od mysql - które zostało skasowane w PHP7.
Pyton_000
Cytat(KsaR @ 15.08.2016, 23:50:46 ) *
Jeśli wielkość liter jest obojętna użyj strpos zamiast stripos, jest szybsze bo nie porównuje wielkości liter.

Nie wiem co ćpiesz tongue.gif

Cytat
stripos — Find the position of the first occurrence of a case-insensitive substring in a string
Damonsson
Cytat(KsaR @ 15.08.2016, 23:50:46 ) *
count + for bym zamienił na pętlę foreach.

count+for jest szybsze niż foreach, na naprawdę sporych danych ta różnica zaczyna być widoczna. Nie wiem jak w PHP7.
KsaR
Cytat(Pyton_000 @ 16.08.2016, 08:29:14 ) *
Nie wiem co ćpiesz tongue.gif

O 24 prawie, bez kawy to ja nie myślę.

Ale i tak się trzymam tego że strpos szybsze.
https://eval.in/623512
--
Co do foreach vs for+count.
Tu za duzo do testowania ale kiedyś testowałem to foreach było szybsze.
Jednak dane były niewielkie (do 100) więc może masz rację.
Pyton_000
Ja nie powiedziałem które szybsze smile.gif strpos szybsze będzie bo nie konwertuje stringów a stripos zapewne to robi (konwertując wsio do małych)
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.