Spróbowałbym uprościć to CAŁKOWICIE, umieszczając wyzwalacze na innych twoich tabelach i po prostu dodając kilka kolumn do tabeli User_Fans... Po jednej dla każdej odpowiedniej count(), którą próbujesz uzyskać... z postów, postów, polubień, komentarzy, Dodaj komentarz lubi.
Kiedy rekord zostanie dodany do dowolnej tabeli, po prostu zaktualizuj swoją tabelę user_fans, aby dodać 1 do liczby... i tak będzie to praktycznie natychmiastowe na podstawie identyfikatora klucza użytkownika. Jeśli chodzi o „LUBIE”... Podobnie, tylko pod warunkiem, że coś zostanie wywołane jako „Lubię to”, dodaj 1. Wtedy zapytanie będzie bezpośrednią matematyką na pojedynczym rekordzie i nie będzie polegać na JAKICHKOLWIEK złączeniach w celu obliczenia „ważona” wartość całkowita. W miarę jak Twoja tabela staje się jeszcze większa, zapytania również stają się dłuższe, ponieważ mają więcej danych do przelania i agregacji. Przechodzisz przez KAŻDY rekord user_fan, który w istocie odpytuje każdy rekord ze wszystkich innych tabel.
Biorąc to wszystko pod uwagę, zachowując tabele tak, jak je masz, zmieniłbym strukturę w następujący sposób...
SELECT
uf.user_name,
uf.user_id,
@pc := coalesce( PostSummary.PostCount, 000000 ) as PostCount,
@pl := coalesce( PostLikes.LikesCount, 000000 ) as PostLikes,
@cc := coalesce( CommentSummary.CommentsCount, 000000 ) as PostComments,
@cl := coalesce( CommentLikes.LikesCount, 000000 ) as CommentLikes,
@pc + @cc AS sum_post,
@pl + @cl AS sum_like,
@pCalc := (@pc + @cc) * 10 AS post_cal,
@lCalc := (@pl + @cl) * 5 AS like_cal,
@pCalc + @lCalc AS `total`
FROM
( select @pc := 0,
@pl := 0,
@cc := 0,
@cl := 0,
@pCalc := 0
@lCalc := 0 ) sqlvars,
user_fans uf
LEFT JOIN ( select user_id, COUNT(*) as PostCount
from post
group by user_id ) as PostSummary
ON uf.user_id = PostSummary.User_ID
LEFT JOIN ( select user_id, COUNT(*) as LikesCount
from post_likes
group by user_id ) as PostLikes
ON uf.user_id = PostLikes.User_ID
LEFT JOIN ( select user_id, COUNT(*) as CommentsCount
from post_comment
group by user_id ) as CommentSummary
ON uf.user_id = CommentSummary.User_ID
LEFT JOIN ( select user_id, COUNT(*) as LikesCount
from post_comment_likes
group by user_id ) as CommentLikes
ON uf.user_id = CommentLikes.User_ID
ORDER BY
`total` DESC
LIMIT 20
My variables are abbreviated as
"@pc" = PostCount
"@pl" = PostLikes
"@cc" = CommentCount
"@cl" = CommentLike
"@pCalc" = weighted calc of post and comment count * 10 weighted value
"@lCalc" = weighted calc of post and comment likes * 5 weighted value
LEFT JOIN do zapytań wstępnych uruchamia te zapytania RAZ, a następnie całość jest łączona zamiast trafienia jako podzapytanie dla każdego rekordu. Używając funkcji COALESCE(), jeśli nie ma takich wpisów w wynikach tabeli LEFT JOINed, nie dostaniesz trafienia z wartościami NULL zakłócającymi obliczenia, więc ustawiłem je domyślnie na 000000.
WYJAŚNIENIE TWOICH PYTAŃ
Możesz mieć dowolne QUERY jako „AS AliasResult”. „As” można również użyć do uproszczenia długich nazw tabel w celu zwiększenia czytelności. Aliasy mogą również używać tej samej tabeli, ale jako innego aliasu, aby uzyskać podobną zawartość, ale w innym celu.
select
MyAlias.SomeField
from
MySuperLongTableNameInDatabase MyAlias ...
select
c.LastName,
o.OrderAmount
from
customers c
join orders o
on c.customerID = o.customerID ...
select
PQ.SomeKey
from
( select ST.SomeKey
from SomeTable ST
where ST.SomeDate between X and Y ) as PQ
JOIN SomeOtherTable SOT
on PQ.SomeKey = SOT.SomeKey ...
Teraz trzecie zapytanie powyżej nie jest praktyczne i wymaga (pełnego zapytania, którego rezultatem jest alias "PQ" reprezentujący "PreQuery" ). Można to zrobić, jeśli chcesz wstępnie ograniczyć pewien zestaw innych złożonych warunków i chcesz mieć mniejszy zestaw PRZED wykonaniem dodatkowych złączeń do wielu innych tabel dla wszystkich wyników końcowych.
Ponieważ "FROM" NIE MUSI być rzeczywistą tabelą, ale może być zapytaniem samym w sobie, w dowolnym innym miejscu zapytania, musi wiedzieć, jak odwołać się do tego zbioru wyników wstępnego zapytania.
Ponadto, podczas wykonywania zapytań w polach, one również mogą być „jako nazwakolumny końcowej”, aby uprościć wyniki tam, gdzie będą również używane.
selectCONCAT( Użytkownik.Zwrot grzecznościowy, Użytkownik.Nazwisko ) as CourtesyNamefrom ...
selectOrder.NonTaxable+ Order.Taxable+ ( Order.Taxable * Order.SalesTaxRate ) jako OrderTotalWithTaxfrom ...
Nazwa kolumny „Jako” NIE jest wymagana jako agregacja, ale najczęściej jest tak postrzegana.
Teraz, w odniesieniu do zmiennych MySQL... Jeśli wykonywałeś procedurę składowaną, wiele osób zadeklaruje, że ustawiają one domyślne wartości przed resztą procedury. Możesz je wykonać w zapytaniu, ustawiając i nadając wynikowi odwołanie „Alias”. Podczas wykonywania tych zmiennych, select będzie symulować zawsze zwracanie wartości POJEDYNCZEGO REKORDU. To prawie jak pojedynczy rekord z możliwością aktualizacji, używany w zapytaniu. Nie musisz stosować żadnych konkretnych warunków „Połącz”, ponieważ może to nie mieć żadnego wpływu na pozostałe tabele w zapytaniu... Zasadniczo tworzy wynik kartezjański, ale jeden rekord z dowolną inną tabelą nigdy nie zostanie utworzony i tak powiela się, więc nie ma żadnych uszkodzeń.
select
...
from
( select @SomeVar := 0,
@SomeDate := curdate(),
@SomeString := "hello" ) as SQLVars
Teraz, jak działają sqlvary. Pomyśl o programie liniowym... Jedno polecenie jest wykonywane w dokładnej kolejności w trakcie wykonywania zapytania. Ta wartość jest następnie ponownie przechowywana w rekordzie „SQLVars”, gotowa do następnego przejścia. Jednak nie odwołujesz się do niego jako SQLVars.SomeVar lub SQLVars.SomeDate... tylko @SomeVar :=someNewValue. Teraz, gdy @var jest używany w zapytaniu, jest również przechowywany jako „As ColumnName” w zestawie wyników. Czasami może to być tylko zastępcza wartość obliczona podczas przygotowywania następnego rekordu. Każda wartość jest wtedy bezpośrednio dostępna dla następnego wiersza. Tak więc, biorąc pod uwagę następującą próbkę...
select
@SomeVar := SomeVar * 2 as FirstVal,
@SomeVar := SomeVar * 2 as SecondVal,
@SomeVar := SomeVar * 2 as ThirdVal
from
( select @SomeVar := 1 ) sqlvars,
AnotherTable
limit 3
Will result in 3 records with the values of
FirstVal SecondVal ThirdVal
2 4 8
16 32 64
128 256 512
Zwróć uwagę, w jaki sposób używana jest wartość @SomeVar, ponieważ używa jej każda kolumna... Więc nawet w tym samym rekordzie zaktualizowana wartość jest natychmiast dostępna dla następnej kolumny... To powiedziawszy, teraz spójrz na próbę zbudowania symulowanej liczby rekordów / ranking na każdego klienta...
select
o.CustomerID,
o.OrderID
@SeqNo := if( @LastID = o.CustomerID, @SeqNo +1, 1 ) as CustomerSequence,
@LastID := o.CustomerID as PlaceHolderToSaveForNextRecordCompare
from
orders o,
( select @SeqNo := 0, @LastID := 0 ) sqlvars
order by
o.CustomerID
Klauzula „Order By” wymusza najpierw zwrócenie wyników w kolejności. Tak więc tutaj zwracane są rekordy na klienta. Za pierwszym razem LastID to 0, a identyfikator klienta to...5. Ponieważ jest inny, zwraca 1 jako @SeqNo, WTEDY zachowuje ten identyfikator klienta w polu @LastID dla następnego rekordu. Teraz następny rekord dla klienta... Ostatni identyfikator jest taki sam, więc przyjmuje @SeqNo (teraz =1), dodaje 1 do 1 i staje się numerem 2 dla tego samego klienta... Kontynuuj ścieżką... .
Jeśli chodzi o poprawę umiejętności pisania zapytań, spójrz na znacznik MySQL i przyjrzyj się niektórym częstym współpracownikom. Przyjrzyj się pytaniom i niektórym złożonym odpowiedziom oraz temu, jak działa rozwiązywanie problemów. Nie znaczy to, że nie ma innych osób o niższych wynikach reputacji, które dopiero zaczynają i są całkowicie kompetentne, ale przekonasz się, kto udziela dobrych odpowiedzi i dlaczego. Spójrz też na ich historię opublikowanych odpowiedzi. Im więcej czytasz i śledzisz, tym lepiej radzisz sobie z pisaniem bardziej złożonych zapytań.