Jag skulle försöka förenkla detta HELT genom att sätta triggers på dina andra tabeller, och bara lägga till några kolumner i din User_Fans-tabell... En för varje respektive count() du försöker få... från Posts, PostLikes, PostComments, PostkommentarGillas.
När en post läggs till i vilken tabell som helst, uppdatera bara din user_fans-tabell för att lägga till 1 till antalet... det kommer att vara praktiskt taget omedelbart baserat på användarens nyckel-ID i alla fall. När det gäller "LIKES"... Liknande, bara under förutsättning att något triggas som ett "Gilla", lägg till 1.. Då kommer din fråga att vara en direkt matematik på den enskilda posten och inte förlita sig på NÅGON kopplingar för att beräkna en "vägt" totalt värde. När din tabell blir ännu större, kommer frågorna också att bli längre eftersom de har mer data att strömma igenom och sammanställa. Du går igenom VARJE user_fan-post som i huvudsak frågar efter varje post från alla andra tabeller.
Med detta sagt, om jag behåller tabellerna som du har dem, skulle jag strukturera om enligt följande...
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 till prequeries kör dessa frågor EN GÅNG, sedan sammanfogas hela saken istället för att träffas som en underfråga för varje post. Genom att använda COALESCE(), om det inte finns några sådana poster i LEFT JOINed-tabellresultaten, kommer du inte att drabbas av NULL-värden som förstör beräkningarna, så jag har ställt in dem som standard till 000000.
KLARIFIERING AV DINA FRÅGOR
Du kan ha vilken QUERY som helst som ett "SOM AliasResult". "Som" kan också användas för att förenkla alla långa tabellnamn för enklare läsbarhet. Alias kan också använda samma tabell men som ett annat alias för att få liknande innehåll, men för olika ändamål.
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 ...
Nu är den tredje frågan ovan inte praktisk och kräver den (fullständiga frågan som resulterar i alias "PQ" som representerar "PreQuery"). Detta kan göras om du ville förbegränsa en viss uppsättning andra komplexa villkor och ville ha en mindre uppsättning INNAN du gör extra kopplingar till många andra tabeller för alla slutresultat.
Eftersom en "FRÅN" inte MÅSTE vara en faktisk tabell, utan kan vara en fråga i sig själv, vilken annan plats som helst som används i frågan, måste den veta hur man refererar till denna förfrågans resultatuppsättning.
När du frågar efter fält kan de också vara "As FinalColumnName" för att förenkla resultaten där de kommer att användas också.
välj CONCAT(Användare.Hälsning, Användare.Efternamn ) som CourtesyNamefrån ...
selectOrder.NonTaxable+ Order.Taxable+ ( Order.Taxable * Order. SalesTaxRate ) som OrderTotalWithTaxfrom ...
Kolumnen "Som" måste INTE vara ett aggregat, men ses oftast på det sättet.
Nu, med avseende på MySQL-variablerna... Om du gjorde en lagrad procedur, kommer många att fördeklarera att de ställer in sina standardvärden innan resten av proceduren. Du kan göra dem direkt i en fråga genom att bara ställa in och ge det resultatet en "Alias"-referens. När du gör dessa variabler, kommer select att simulera att alltid returnera ett SINGLE RECORD värde av värdena. Det är nästan som en uppdateringsbar enskild post som används i frågan. Du behöver inte tillämpa några specifika "Join"-villkor eftersom det kanske inte har någon betydelse för resten av tabellerna i en fråga... Skapar i huvudsak ett kartesiskt resultat, men en post mot någon annan tabell kommer aldrig att skapas duplicerar hur som helst, så ingen skada nedströms.
select
...
from
( select @SomeVar := 0,
@SomeDate := curdate(),
@SomeString := "hello" ) as SQLVars
Nu, hur sqlvars fungerar. Tänk på ett linjärt program... Ett kommando exekveras i exakt ordningsföljd när frågan körs. Det värdet återlagras sedan tillbaka i "SQLVars"-posten redo för nästa gång. Du hänvisar dock inte till det som SQLVars.SomeVar eller SQLVars.SomeDate... bara @SomeVar :=someNewValue. Nu, när @var används i en fråga, lagras den också som ett "As ColumnName" i resultatuppsättningen. Ibland kan detta bara vara ett platshållarberäknat värde för att förbereda nästa post. Varje värde är sedan direkt tillgängligt för nästa rad. Så, givet följande exempel...
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
Lägg märke till hur värdet för @SomeVar används när varje kolumn använder det... Så även på samma post är det uppdaterade värdet omedelbart tillgängligt för nästa kolumn... Som sagt, titta nu på att försöka bygga en simulerad posträkning / ranking per varje kund...
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
"Order By"-satsen tvingar resultaten att returneras i sekvens först. Så här returneras uppgifterna per kund. Första gången är LastID 0 och kund-ID är säg...5. Eftersom olika, returnerar den 1 som @SeqNo, DÅ bevarar den det kund-ID:t i @LastID-fältet för nästa post. Nu, nästa post för kund... Senaste ID är detsamma, så det tar @SeqNo (nu =1), och lägger till 1 till 1 och blir #2 för samma kund... Fortsätt på vägen. .
När det gäller att bli bättre på att skriva frågor, ta en titt på MySQL-taggen och titta på några av de tunga bidragsgivarna. Titta på frågorna och några av de komplexa svaren och hur problemlösning fungerar. För att inte säga att det inte finns andra med lägre anseende som precis har börjat och är helt kompetenta, men du kommer att se vem som ger bra svar och varför. Titta på deras historik över postade svar också. Ju mer du läser och följer, desto mer kommer du att få bättre grepp om att skriva mer komplexa frågor.