Proverei a semplificarlo COMPLETAMENTE inserendo trigger sulle altre tabelle e aggiungendo solo alcune colonne alla tabella User_Fans... Una per ogni rispettivo conteggio() che stai cercando di ottenere... da Posts, PostLikes, PostComments, PostCommentMi piace.
Quando un record viene aggiunto a qualsiasi tabella, aggiorna semplicemente la tua tabella user_fans per aggiungere 1 al conteggio... sarà comunque praticamente istantaneo in base all'ID chiave dell'utente. Per quanto riguarda i "MI PIACE"... Simile, solo a condizione che qualcosa venga attivato come "Mi piace", aggiungi 1.. Quindi la tua query sarà una matematica diretta sul singolo record e non si baserà su QUALSIASI join per calcolare un valore totale "pesato". Man mano che la tua tabella diventa ancora più grande, anche le query diventeranno più lunghe poiché hanno più dati da trasferire e aggregare. Stai esaminando OGNI record user_fan che in sostanza sta interrogando ogni record da tutte le altre tabelle.
Detto questo, mantenendo i tavoli come li avete voi, io ristrutturerei così...
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 to prequery esegue queste query UNA VOLTA, quindi l'intero oggetto viene unito invece di essere colpito come sottoquery per ogni record. Usando COALESCE(), se non ci sono voci di questo tipo nei risultati della tabella LEFT JOINed, non verrai colpito con valori NULL che incasinano i calcoli, quindi li ho impostati per impostazione predefinita su 000000.
CHIARIMENTO DELLE TUE DOMANDE
Puoi avere qualsiasi QUERY come "AS AliasResult". Il "As" può essere utilizzato anche per semplificare i nomi di tabelle lunghe per una leggibilità più semplice. Gli alias possono anche utilizzare la stessa tabella ma come un alias diverso per ottenere contenuti simili, ma per scopi diversi.
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 ...
Ora, la terza query sopra non è pratica richiedendo la ( query completa risultante in alias "PQ" che rappresenta "PreQuery" ). Questo può essere fatto se si desidera pre-limitare un determinato insieme di altre condizioni complesse e si desidera un insieme più piccolo PRIMA di eseguire join aggiuntivi a molti altri tavoli per tutti i risultati finali.
Poiché un "FROM" non DEVE essere una tabella effettiva, ma può essere una query in sé, qualsiasi altro luogo utilizzato nella query, deve sapere come fare riferimento a questo set di risultati di prequery.
Inoltre, quando si eseguono query sui campi, anch'essi possono essere "As FinalColumnName" per semplificare i risultati ovunque verranno utilizzati.
selectCONCAT( User.Salutation, User.LastName ) come CourtesyNameda ...
selectOrder.Non Taxable+ Order.Taxable+ ( Order.Taxable * Order.SalesTaxRate ) come OrderTotalWithTaxfrom ...
Il nome della colonna "As" NON deve essere un aggregato, ma è più comunemente visto in questo modo.
Ora, per quanto riguarda le variabili MySQL... Se stavi eseguendo una procedura memorizzata, molte persone le dichiareranno in anticipo impostando i loro valori predefiniti prima del resto della procedura. Puoi eseguirli in linea in una query semplicemente impostando e fornendo al risultato un riferimento "Alias". Quando si eseguono queste variabili, select simulerà sempre restituendo un SINGOLO RECORD dei valori. È quasi come un singolo record aggiornabile utilizzato all'interno della query. Non è necessario applicare condizioni di "Unisci" specifiche in quanto potrebbe non avere alcun effetto sul resto delle tabelle in una query... In sostanza, crea un risultato cartesiano, ma un record rispetto a qualsiasi altra tabella non verrà mai creato duplica comunque, quindi nessun danno a valle.
select
...
from
( select @SomeVar := 0,
@SomeDate := curdate(),
@SomeString := "hello" ) as SQLVars
Ora, come funzionano gli sqlvar. Pensa a un programma lineare... Un comando viene eseguito nella sequenza esatta durante l'esecuzione della query. Tale valore viene quindi ripristinato nel record "SQLVars" pronto per la prossima volta. Tuttavia, non lo fai riferimento come SQLVars.SomeVar o SQLVars.SomeDate... solo @SomeVar :=someNewValue. Ora, quando @var viene utilizzato in una query, viene anche archiviato come "As ColumnName" nel set di risultati. A volte, questo può essere solo un valore calcolato segnaposto in preparazione del record successivo. Ogni valore è quindi direttamente disponibile per la riga successiva. Quindi, dato il seguente esempio...
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
Nota come viene utilizzato il valore di @SomeVar poiché ogni colonna lo utilizza ... Quindi anche sullo stesso record, il valore aggiornato è immediatamente disponibile per la colonna successiva ... Detto questo, ora prova a creare un conteggio di record simulato / classifica per ogni cliente...
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
La clausola "Ordina per" impone che i risultati vengano restituiti prima in sequenza. Quindi, qui vengono restituiti i record per cliente. La prima volta, LastID è 0 e l'ID cliente è dire...5. Poiché diverso, restituisce 1 come @SeqNo, POI conserva quell'ID cliente nel campo @LastID per il record successivo. Ora, record successivo per il cliente... L'ultimo ID è lo stesso, quindi prende @SeqNo (ora =1) e aggiunge 1 a 1 e diventa il numero 2 per lo stesso cliente... Continua sul percorso.. .
Per migliorare la scrittura delle query, dai un'occhiata al tag MySQL e dai un'occhiata ad alcuni dei maggiori contributori. Esamina le domande e alcune delle risposte complesse e come funziona la risoluzione dei problemi. Per non dire che non ci sono altri con punteggi di reputazione più bassi appena agli inizi e completamente competenti, ma troverai chi dà buone risposte e perché. Guarda anche la loro cronologia delle risposte pubblicate. Più leggi e segui, più riuscirai a gestire meglio la scrittura di query più complesse.