[PHP] - Jaką funkcją policzyć pobrane wyniki z bazy?

Potrzebne do policzenia komentarzy :slight_smile:

 

Pozdrawiam

<?php
    $komenty_pobierz = mysql_query("SELECT * FROM comments WHERE news_id='".$id."'"); // pobieranie wszystkich komentów
    $komenty_ilosc = mysql_num_rows($komenty_pobierz); // pobranie liczby pobranych komentów
    echo "$komenty_ilosc"; // wypisanie liczby komentów :)
?>

Bardzo łatwo poszło :stuck_out_tongue: Żadne tam drobokowe COUNT nie było mi potrzebne :) Komuś się może przydać :slight_smile:

Weź pod uwagę, że pobierasz z bazy wszystkie wartości z tabeli, nie używasz ich. Zużywasz transfer :stuck_out_tongue:

@jacko1998 To jest niewydajne.

To jak zrobić by było wydajne ? Przecież muszę pobrać najpierw wszystkie (z jakimś tam id) i potem je policzyć/zsumować (mysql_num_rows), żeby wypisać ile ich jest. Masz na myśli ten COUNT ? Jeśli tak, to podałbyś linka, gdzie dowiedział bym się jak to zrobić z tym COUNTEM.

Znajdź na tutejszym blogu wpis użytkownika @tfl na ten temat. Jest też tam mój komentarz w którym radziłem mu co poprawić. Generalnie chodzi o to, że ilość komentarzy trzymać jako pole, i zwiększać, przy dodawaniu komentarza. Wtedy nic nie liczymy, mamy to z cache-owane. Moja porada dotyczyła, żeby było to w jednej transakcji, aby nie doszło do rozspójnienia danych.

Czyli chodzi Ci o pętlę ? Też o tym myślałem, ale uznałem to za zbyt trudne zadanie i poszedłem na łatwiznę. A powiesz może, kiedy przy moim aktualnym skrypcie, zaczął bym odczuwać, że to wolno chodzi ? (tj ile musiało by być komentarzy, abym coś zauważył.)

Nie o to mi chodzi. Robisz dwa query, jedno dodaje komentarz, a drugie w tabeli newsa dodaje w kolumnie ilości_komentarzy ze komentarzy jest o jeden więcej, wtedy wystarczy ze pobierzesz to pole. Tylko jeśli coś się wysypie miedzy kolejnymi query, to będzie problem. Więc trzeba to zrobić w transakcji.

Czyli muszę, stworzyć nową tabelę, tylko po to by tam trzymać ilość_komntarzy ? Bo w jednej można tylko mieć jedno pole z A_I ;/

Dobra użyj tego mysql_rows_count…

newsy

id                          tytuł                         ilość komentów
----------------------------------------------------------------------
1         "lol"                                                2
2         "nigdy nie będę programistą"               1

2227896700_1385762243_thumb.jpg

To może powiesz mi, jak dodać mam od tej tabeli, drugą kolumnę z A_I ? Przecież to ma być zautomatyzowane.

 

@UP: Ahaaaaaaaaaaa. Ja mam zrobić update kolumny, po dodaniu newsa.  #-o :glupek2:  :glupek2:

Raczej po dodaniu komentarza. Ale tak. O ile jest szybciej tobie nie podam, ale większość CMSów z tego tricku korzysta. Jeśli chcesz liczby, odnajdź ten wpis na blogu DP.

nie ma żadnego sensu przepychać takich ilości danych skoro można pobrać gotową liczbę

SELECT COUNT(news_id) FROM comments WHERE news_id='".$id."'

@pain3hp

To jest dość plastyczne rozwiązanie, przecież nie pobiera się *, ani nie pobiera się danych bez limitu. Stworzę sobie klasę, robię query z limitem i mam twój kursor. Oczywiście tylko i wyłącznie gdy tego potrzebuje, by nie przeciążać serwera zapytaniami. Co do trzymania ilości wpisów, count nie liczy on zwraca wartość. MySQL przetrzymuje ilość wierszy w bazie. Dlatego odwołujemy się do bazy a nie do wszystkich rekordów z ilością wierszy.

 

Co do zliczania w zmiennej tymczasowej, to mija się z celem. Tworząc stronę tworzysz cache by nie odwoływać się do bazy za każdym razem o to samo, więc po co cache który będzie używany do kolejnego cache ? Zwiększam ilość zapytań :))

@drobok

Istnieje pewna zasada, nie znam się, nie wtrącam się. Zastosuj się do niej.

 

Większej głupoty nie słyszałem, jeśli chcesz pobrać wszystkie informacje z wiersza pobierasz je z ‘*’. A dane nie są bez limitu 20 GB to bardzo mała hurtownia danych.

 

Widać, że nie rozumiesz jak to działa. Dane są już przygotowane, tylko jeszcze nie przesłane z bazy do aplikacji. Swoim limitem, będziesz obciążał bazę, bo każde nowe zapytanie będzie przechodzić cały zbiór w poszukiwaniu dopasowania. Upewnij się tylko, że w swojej indolencji użyjesz prepared statement, co by dodatkowo nie obciążać aplikacji, przez kompilowanie zapytania w kółko.

 

Tak. Dla całej tabeli trzyma ilość wierszy. Może nie zauważyłeś my nie chcemy wszystkich wierszy tylko te o odpowiednim kluczu obcym (ile jest komentarzy do konkretnego newsa). To też jest trzymane? Pff…

Dobra rada dla ciebie znajdź tę serię stworzoną przez użytkownika @tfl i się dokształć. Ten cache jest wykorzystywany w prawie każdym CMS-ie.

 

Jaki to “normalny język, w którym nawiązane połączenie zwraca kursor”? Bo to, że jakaś bibloteka dostepu do baz danych, dostępna dla jakiegoś języka, potrafiłaby taki kursor zwrócić, to jeszcze brzmiałoby sensownie.

O jakim w ogóle kursorze mowa? Bazodanowym, czy jakiejś strukturze na poziomie biblioteki/języka programowania?

Z tą normalnością też przesadzasz - normalne jest to, że nawiązane połączenie, zwraca nawiązane i otwarte połączenie, na którym można wykonywać zapytania.

 

 

 

Jakie to niby obciążenie dla bazy wykonanie zapytania z where po indeksowanej kolumnie?

 

Co z wydajnością samych kursorów i trzymania otwartego połączenia do bazy?

 

Każdym CMSie napisanym w PHP? Bo stosowanie paginacji przy pobieraniu danych jest raczej normalnym podejściem w każdej aplikacji webowej. Dlaczego niby po stronie aplikacji miałaby nas interesować wewnętrzna struktura bazy danych, jakiejś kursory i w ogóle SQL?

 

O unit of work słyszałeś?

Np. Java + JDBC? http://stackoverflow.com/a/3682667 oraz http://jdbc.postgresql.org/documentation/head/query.html#fetchsize-example

Generalnie wyobraź sobie, że wykonujesz zapytanie na bazie, które zwróci ResultSet zbyt duży, żeby zmieścił się w pamięci. Jeśli aplikacja w tym momencie próbuje zaciągnąć z bazy wszystko naraz to można umrzeć. Wystarczy ze wyciągnie powiedzmy 1000 pierwszych wierszy, a kiedy ja będę tworzył te obiekty w while pytając o next, będą dociągane następne (oczywiście niepojedynczo, ale jakiś payload). Czemu to jest dobre?

  1. Jeśli rekordów jest dużo to muszę czekać, zamiast działać ad hoc

  2. Być może przejrzę pierwsze 10% i stwierdzę (algorytm), że w sumie mam tego czego szukałem pozostałe 90% nie jest mi potrzebne.

 

 

  1. Rozumiesz, że mówimy o kolumnie klucza obcego. Czyli takiej kolumnie, gdzie potencjalnie wiele wartości może się powtarzać, a biorąc pod uwagę, że to komentarze, to jest bardzo prawdopodobnym, że komentarzy może być dużo pod newsem? Więc może taki super skrócony wykład z baz danych, indeks zakładamy na kolumnie, gdzie wartości są  różne. Inaczej efekt będzie odwrotny do oczekiwanego.

  2. Załóżmy, taki prosty przykład, że masz tabelę z jedną kolumną i w niej liczbę, przy czym wierszy jest tyle, że jak to pobierzesz, to nie zmieści ci się do RAMu. Chcemy dać odpowiedź na pytanie ile wynosi suma tych wszystkich liczb.

Wasze podejście stwierdza by użyć SQL-owego SUM na kolumnie, co zwróci poprawny wynik. Ale jest wolne. Bo wiedząc, że będę tej sumy potrzebował, lepiej jest trzymać jakieś pole, w którym jeśli dodasz albo usuniesz wiersz z tej tabeli z liczbami, to zmodyfikujesz wartość tej sumy o stosowną wartość. Tym samym będziesz mógł pobierać ją w czasie stałym. Tylko o to się rozchodzi. By trzymać przy newsie liczbę komentarzy, bo jest to szybsze.

  1. O unity of work nie słyszałem. Ale przeczytałem właśnie. W każdym razie używałem tego podejścia, nie znając jego nazwy. Bazodanowy kursor pozwala ci robić to co ono wyszczególnia:

 

w sposób transparentny, bądź przy minimalnej konfiguracji (patrz linki) w obie strony (zapis/odczyt).

LIMIT/OFFSET używasz, gdy chcesz faktycznie pobrać jakiś przedział danych, np. do paginacji. Ale jeśli chcesz pobrać wszystko, by “w locie” coś na tym przeliczać używa się faktu, że nie jest ściągane wszystko, tylko jakaś buforowana część. Robienie w tym momencie LIMIT spowalnia widocznie proces.

Żebyśmy się dobrze zrozumieli, nie jestem piewcą PHP, bardziej hejterem, ale znać je muszę - niestety. Dlatego też mówię, że jeśli PHP jest normalne (w co wątpię), to umożliwi podobną technologię, z tego kursora możesz pobrać ile jest wierszy zwróconych przez zapytanie, a nie pobierać ich fizycznie. Dlatego jeśli jest coś takiego zaimplementowane to czy użyjemy mysql_num_rows, czy COUNT() wyjdzie na jedno bo nie ściągamy wierszy, żeby policzyć ile ich jest.

 

Czyli nie język, lecz biblioteka. Uff.

 

Dlaczego zatem miałbym chcieć coś takiego robić?

Nie jest to na pewno potrzebne do wyświetlania czegokolwiek użytkownikowi, bo jemu wystarczy góra kilkadziesiąt wierszy na raz, a to się rozwiązuje zwykłą paginacją.

Może to być potrzebne tylko dla jakiegoś wsadowego przetwarzania danych. Ale gdyby ilość takich danych stanowiła jakiś problem dla aplikacji, to pomyślałbym raczej o napisaniu procedury składowanej i zrobieniu wszystkiego po stronie DBMS.

 

Dlatego właśnie na kolumny kluczy obcych często zakłada się indeksy, bo wartości w nich są dobrze zróżnicowane i selektywność takich indeksów jest wysoka.

 

Nie pisz do mnie o “waszym podejściu”, bo ja się w tej kwestii nie wypowiadałem.

I nie twierdzę, że trzymanie dodatkowej kolumny z liczbą komentarzy jest złe. Powiem nawet, że czasem może być dobre. Z drugiej strony jest redundantne, więc może prowadzić do niespójności. A po co nam niespójności w bazie? I ile tych komentarzy będzie? Nie aż tak dużo, żeby pojedynczy dodatkowy count miał jakiekolwiek znaczenie dla aplikacji.

Twój pomysł zalatuje przedwczesną i prawdopodobnie zbędną w tym przypadku optymalizacją.

W ogóle piszesz tak, jakby wszystko było proste, oczywiste i istniało tylko jedno słuszne podejście. Tymczasem, o tym, co jest dobre, a co złe, decyduje konkretny przypadek aplikacji i bazy danych, oraz profiler i plany wykonania zapytania.

 

Unit of work to podejście związane z programowaniem obiektowym, w którym chodzi o to, że zestaw powiązanych ze sobą operacji biznesowych wykonujemy w ramach jednej transakcji z bazą danych. Trzymanie otwartego kursora i transakcji jest raczej odwrotnością UoW.

Pobranie counta na tabeli gdzie jest założony odpowiedni indeks to jest tutaj chyba najszybszym rozwiazanieim I najmniej obciazajacym bazę i łącze. Pobieranie wszystkiego i potem zliczanie wierszy to wręcz przykład jak tego nie robić. Sensowne też jest trzymanie dodatkowej kolumny z ilością komentarzy. Przy insercie dodaj trigger powiekszajacy to pole o jeden. Będzie o szybkie(insertów jest raczej mniej niż selectow) i w miare lekkie.