Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie kann man die Abfrage optimieren, wenn die Tabelle 10000 Einträge mit MySQL enthält?

Ich würde versuchen, dies VOLLSTÄNDIG zu vereinfachen, indem ich Trigger in Ihre anderen Tabellen einfüge und Ihrer User_Fans-Tabelle nur ein paar Spalten hinzufüge ... Eine für jede entsprechende Anzahl(), die Sie erhalten möchten ... von Posts, PostLikes, PostComments, PostCommentLikes.

Wenn ein Datensatz zu welcher Tabelle hinzugefügt wird, aktualisieren Sie einfach Ihre user_fans-Tabelle, um 1 zur Zählung hinzuzufügen ... es wird sowieso praktisch sofort basierend auf der Schlüssel-ID des Benutzers sein. Wie für die "LIKES" ... Ähnlich, nur unter der Bedingung, dass etwas als "Like" ausgelöst wird, fügen Sie 1 hinzu „gewichteter“ Gesamtwert. Wenn Ihre Tabelle noch größer wird, werden auch die Abfragen länger, da sie mehr Daten zu verarbeiten und zu aggregieren haben. Sie gehen JEDEN user_fan-Datensatz durch, der im Wesentlichen jeden Datensatz aus allen anderen Tabellen abfragt.

Abgesehen davon würde ich, wenn Sie die Tabellen so belassen, wie Sie sie haben, wie folgt umstrukturieren ...

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

Der LEFT JOIN zu Vorabfragen führt diese Abfragen EINMAL durch, dann wird das Ganze verbunden, anstatt als Unterabfrage für jeden Datensatz getroffen zu werden. Durch die Verwendung von COALESCE() werden Sie, wenn es keine solchen Einträge in den LEFT JOINed-Tabellenergebnissen gibt, nicht von NULL-Werten getroffen, die die Berechnungen durcheinander bringen, also habe ich sie auf 000000 voreingestellt.

KLÄRUNG IHRER FRAGEN

Sie können jede QUERY als "AS AliasResult" haben. Das "As" kann auch verwendet werden, um lange Tabellennamen für eine einfachere Lesbarkeit zu vereinfachen. Aliasse können auch dieselbe Tabelle verwenden, aber als einen anderen Alias, um ähnlichen Inhalt zu erhalten, aber für einen anderen Zweck.

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 ...

Nun, die dritte obige Abfrage ist nicht praktikabel und erfordert die ( vollständige Abfrage, die zum Alias ​​"PQ" führt, der "PreQuery" darstellt). Dies könnte getan werden, wenn Sie einen bestimmten Satz anderer komplexer Bedingungen im Voraus einschränken und einen kleineren Satz wünschen, BEVOR Sie zusätzliche Verknüpfungen mit vielen anderen Tabellen für alle Endergebnisse vornehmen.

Da ein "FROM" keine tatsächliche Tabelle sein MUSS, sondern eine eigene Abfrage sein kann, muss es wissen, wie es auf diese Vorabfrage-Ergebnismenge verweisen kann.

Wenn Felder abgefragt werden, können sie auch "As FinalColumnName" sein, um die Ergebnisse dort zu vereinfachen, wo sie auch verwendet werden.

selectCONCAT( User.Salutation, User.LastName ) as CourtesyNamefrom ...

selectOrder.NonTaxable+ Order.Taxable+ ( Order.Taxable * Order.SalesTaxRate ) as OrderTotalWithTaxfrom ...

Der „As“-Spaltenname muss NICHT zwingend ein Aggregat sein, wird aber meistens so gesehen.

Nun zu den MySQL-Variablen ... Wenn Sie eine gespeicherte Prozedur ausführen, werden viele Leute vorab erklären, dass sie ihre Standardwerte vor dem Rest der Prozedur festlegen. Sie können sie inline in einer Abfrage ausführen, indem Sie diesem Ergebnis einfach eine "Alias"-Referenz setzen und zuweisen. Wenn Sie diese Variablen ausführen, simuliert die Auswahl immer einen EINZELNEN RECORD-Wert der Werte. Es ist fast wie ein aktualisierbarer einzelner Datensatz, der in der Abfrage verwendet wird. Sie müssen keine spezifischen "Join"-Bedingungen anwenden, da dies möglicherweise keinen Einfluss auf den Rest der Tabellen in einer Abfrage hat ... Erstellt im Wesentlichen ein kartesisches Ergebnis, aber ein Datensatz gegen eine andere Tabelle wird niemals erstellt sowieso Duplikate, also kein Schaden nachgelagert.

select 
       ...
   from 
      ( select @SomeVar := 0,
               @SomeDate := curdate(),
               @SomeString := "hello" ) as SQLVars

Nun, wie die sqlvars funktionieren. Stellen Sie sich ein lineares Programm vor ... Ein Befehl wird in der exakten Reihenfolge ausgeführt, in der die Abfrage ausgeführt wird. Dieser Wert wird dann wieder im "SQLVars"-Datensatz gespeichert, bereit für den nächsten Durchlauf. Sie referenzieren es jedoch nicht als SQLVars.SomeVar oder SQLVars.SomeDate ... nur @SomeVar :=someNewValue. Wenn die @var jetzt in einer Abfrage verwendet wird, wird sie auch als „As ColumnName“ in der Ergebnismenge gespeichert. Manchmal kann dies nur ein berechneter Platzhalterwert zur Vorbereitung des nächsten Datensatzes sein. Jeder Wert steht dann direkt für die nächste Zeile zur Verfügung. Also, gegeben das folgende Beispiel...

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

Beachten Sie, wie der Wert von @SomeVar verwendet wird, wenn jede Spalte ihn verwendet ... Der aktualisierte Wert ist also selbst für denselben Datensatz sofort für die nächste Spalte verfügbar ... Sehen Sie sich nun an, wie Sie versuchen, eine simulierte Datensatzanzahl zu erstellen / Ranking pro Kunde...

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

Die "Order By"-Klausel erzwingt, dass die Ergebnisse zuerst der Reihe nach zurückgegeben werden. Hier werden also die Datensätze pro Kunde zurückgegeben. Beim ersten Mal ist LastID 0 und die Kunden-ID ist sagen wir ... 5. Da es anders ist, gibt es 1 als @SeqNo zurück, DANN behält es diese Kunden-ID im @LastID-Feld für den nächsten Datensatz bei. Nun, nächster Datensatz für den Kunden ... Die letzte ID ist dieselbe, also nimmt sie die @SeqNo (jetzt =1) und addiert 1 zu 1 und wird #2 für denselben Kunden ... Weiter auf dem Pfad. .

Um beim Schreiben von Abfragen besser zu werden, werfen Sie einen Blick auf das MySQL-Tag und sehen Sie sich einige der großen Mitwirkenden an. Schauen Sie sich die Fragen und einige der komplexen Antworten an und wie das Lösen von Problemen funktioniert. Um nicht zu sagen, dass es nicht andere mit niedrigeren Reputationswerten gibt, die gerade erst anfangen und vollkommen kompetent sind, aber Sie werden feststellen, wer gute Antworten gibt und warum. Sehen Sie sich auch den Verlauf der geposteten Antworten an. Je mehr Sie lesen und befolgen, desto besser können Sie komplexere Abfragen schreiben.