Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: DB Cache
Forum PHP.pl > Forum > PHP
cadavre
Mam kilka pytań dot. cacheowania zapytań DB:

1. Jak rozpoznawać o które SQL chodzi? Ja każde zapytanie strtolow'uję, opróżniam ze znaków ['|"|`] i spacji a potem hash'uję w md5 - hash'em rozpoznaję query i nazywam pliki. Jak zrobić to inaczej, szybciej? Jak wiadomo replace i md5, które korzysta z algorytmów matematycznych, zajmują sporo czasu.
2. Czy sprawdzanie if( $czas_utworzenia_pliku > $aktualny_czas - $interwał ) { z_cache'u } jest dobrym sposobem na sprawdzenie terminu ważności pliku z cache'm?
3. W jaki sposób połączyć klasy db i cache'u? U mnie jeśli zapytanie ma być cache'owane wysyła do własnego fetch'a string, jeśli nie cacheowane - wysyła resource z query. Fetch sprawdza is_string i is_resource. To rozwiązanie jednak do najszybszych nie należy.
4. Pliki z cache'm zapisywać jako zserialiowaną tablicę czy po prostu jako <?php $arr=...; ?> ?
Cezar708
Osobiście zapisuję jako zserializowaną tablicę i sprawdzam datę utworzenia pliku. Nazwę pliku określam na podstawie warunków zapytania... nie jest to zbyt skomplikowane, ale nie narzekam na szybkość. Chętnie poczytam o innych pomysłach.
cadavre
HAHA! laugh.gif Panowie właśnie odzyskałem wiarę w siebie. Rkingsmiley.png Już tłumaczę.
Napisałem sobie śliczniutki skrypcik do cache'owania zapytań z bazy danych. Kod wyglądał bardzo dobrze i wszystko działo - z tym, że jakoś wolno. Postanowiłem zadać pytania zawarte w pierwszym poście (wciąż aktualne) i postanowiłem pousuwać pewne elementy w moim skrypcie lub pozamieniać na stałe (jak np. generowanie md5 sql'a). Tym sposobem robiłem co usunięcie - benchmark czasu zapytania:
  1. SELECT script_time,queries,SUM(queries),AVG(script_time)
  2. FROM statystyka_system WHERE DATA
  3. BETWEEN '2006-12-10 00:00' AND '2006-12-20 00:00'
  4. GROUP BY script_time
[tabela 11,6KB z 324. wpisami]

Oto wyniki:
Kod
mysql_        2,89
mój fetch     3,09
query tp      9,20
query gp      8,67
query tp+bh   8,23
query gp+bh   7,83
query bst     7,50
query nBUG    0,08

tp - tworzenie pliku cache
gp - gotowy plik cache (istniejący)
bh - bez hashowania
bst - bez sprawdzania typu (is_string i is_resource)
nBUG - po znalezieniu błędu w kodzie

Po kolei:
query na systmowych mysql_ (bez cache)
query z moim fetch (bez cache)
query z tworzeniem pliku cache (z cache)
query z utworzonego pliku (z cache)
query z tworzeniem pliku bez hasha (z cache)
query z utworzonego pliku bez hasha (z cache)
query z utworzonego pliku bez hasha, bez sprawdzania typów (z cache)
query po znalezieniu głupiego błędu (z cache)

W/w błąd to odczytywanie za każdym razem pliku z cachem z HDD: każdy row - na nowo odczytany plik. Powodem było "wylezienie" metody read() poza pierwszego if'a. Różnica pomiędzy odczytywaniem z bazy danych to ponad 2,81sekundy!
Dodatkowo co zwalnia system:
Kod
Tworzenie pliku query    +0,50sec
Hashowania zapytania     +0,90sec
Sprawdzanie typów i if   +0,30sec

Teraz tylko muszę powyższe czynniki zmodyfikować by je przyspieszyć (jak na razie dodając je i czas query z cache jest jakieś ~1,78sec więc i tak szybciej niż query z bazy danych).

Gdy tylko wprowadzę poprawki - przedstawię kod i wrzucę do gotowych "Algorytmy, skrypty...".

Na przyszłość:

Czas utworzenia pliku filectime nie oznacza czasu utworzenia pliku, a czas węzła pliku. Zatem jeśli tworzymy plik o takiej samej nazwie na miejsce nowego - data jego utworzenia zostanie zachowania. W systemie cacheowania należy posłużyć się funkcją filemtime. Straciłem przez to g***o z 1h 30min...
msulik
Jeśli mogę dorzucić swoje trzy grosze ;)
Faktycznie md5 zajmuje dużo czasu, co jest raczej oczywiste. Osobiście stosuję do nazywania plików cache czysty słowny opis, np. 'OstatnieDziesiecNewsow', 'MenuGlowne' czy 'UzytkownicyOnLine'. Ewentualnie, gdy zachce mi się kiedyś używać spacji czy innych znaczków, mogę potraktować takie cudo funkcją urlencode (może base64_encode albo jakaś inna byłaby szybsza?) i wydaje mi się, że nie ma w tym nic złego.

Poza tym samo zapytanie SQL może być zależne od jakichś parametrów zmieniających się często, podczas gdy w czasie świeżości cache'u (tzn. gdy cache nie wymaga odświeżenia) wynik zapytania jest taki sam albo różnica w wyniku nie jest dla nas bardzo istotna (na przykład "Newsy z ostatnich 10 minut"; pomijam fakt, że "ostatnie 10 minut" można na sztywno zafiksować w zapytaniu, ale to tylko taki przykład).

Co do serializowania, może ktoś mnie oświeci, czemu tak jest. Początkowo używałem nie serializowania, tylko funkcji var_export() z drugim parametrem ustawionym na true, a następnie przy odczytywaniu cache po prostu includowałem plik z cachem. Wszystko działało pięknie. Ale zrobiłem benchmark i okazało się, że serialize działa o połowę szybciej niż var_export(), również unserialize jest szybsze niż include. Może ktoś wie, czemu tak jest?
cadavre
Aktualnie przerzuciłem się na strtolower i crc32 gdyż ten jest najszybszym (z moich benchmarków) algorytmem.

Co do kwestii "10 ostatnich minut" - nie wszędzie trzeba używać cache'owania, a w takich wypadkach nawet nie jest to wskazane - więcej czasu zajmować będzie tworzenie plików co chwila niż trwać będzie ich odczyt z bazy.

Serialize z tego co się orientuję jest szybszy gdyż jest to konstrukcja zaszyta głęboko w jądro php i przy generacji ciągu czy jego odczytu - funkcja bezpośrednio ładuje dane - bez jakiegokolwiek przekształcania treści ciągu, bez typowania etc.
msulik
Jak się mówi: "Każdemu według potrzeb", więc ja będę się upierał przy swoim ;) Ale dzięki za naprowadzenie na crc32, faktycznie jest najszybsze.

Choć nadal gryzie mnie to serialize - czemu jest szybsze od include, wszak też mocno wbudowanego w php... Może to temat na inny topik (albo poszperanie w źródłach).

Pozdrawiam.
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.