Mysql
 sql >> Database >  >> RDS >> Mysql

Come ottimizzare la query se la tabella contiene 10000 voci utilizzando MySQL?

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.