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

Hvordan optimerer man forespørgslen, hvis tabellen indeholder 10000 poster ved hjælp af MySQL?

Jeg ville forsøge at forenkle dette HELT ved at sætte udløsere på dine andre tabeller, og blot tilføje et par kolonner til din User_Fans-tabel... En for hver respektive count() du forsøger at få... fra Posts, PostLikes, PostComments, PostKommentar Synes godt om.

Når en post tilføjes til hvilken som helst tabel, skal du bare opdatere din user_fans-tabel for at tilføje 1 til antallet... den vil under alle omstændigheder være praktisk talt øjeblikkelig baseret på brugerens nøgle-id. Med hensyn til "LIKES"... Tilsvarende, kun under den betingelse, at noget udløses som et "Like", tilføje 1.. Så vil din forespørgsel være en direkte matematik på den enkelte post og ikke stole på NOGEN joins til at beregne en "vægtet" samlet værdi. Efterhånden som din tabel bliver endnu større, vil forespørgslerne også blive længere, da de har flere data at strømme igennem og samle. Du gennemgår HVER user_fan-post, som i bund og grund forespørger hver post fra alle de andre tabeller.

Når det er sagt, vil jeg omstrukturere som følger, hvis du holder tabellerne som du har dem...

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

VENSTRE JOIN til forespørgsler kører disse forespørgsler EN gang igennem, så samles det hele i stedet for at blive ramt som en underforespørgsel for hver post. Ved at bruge COALESCE(), hvis der ikke er sådanne poster i LEFT JOINed tabelresultaterne, vil du ikke blive ramt af NULL-værdier, der ødelægger beregningerne, så jeg har indstillet dem til 000000 som standard.

AFKLARING AF DINE SPØRGSMÅL

Du kan have en hvilken som helst QUERY som et "SOM AliasResult". "Som" kan også bruges til at forenkle alle lange tabelnavne for lettere læsbarhed. Aliaser kan også bruge den samme tabel, men som et andet alias for at få lignende indhold, men til forskellige formå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 er den tredje forespørgsel ovenfor ikke praktisk og kræver den (fuld forespørgsel, der resulterer i alias "PQ" repræsenterer "PreQuery"). Dette kunne gøres, hvis du ønskede at forhåndsbegrænse et bestemt sæt af andre komplekse forhold og ønskede et mindre sæt, FØR du laver ekstra joins til mange andre tabeller for alle endelige resultater.

Da en "FROM" ikke BEHØVER at være en egentlig tabel, men kan være en forespørgsel i sig selv, et hvilket som helst andet sted, der bruges i forespørgslen, skal det vide, hvordan man refererer til dette forespørgselsresultatsæt.

Når du forespørger felter, kan de også være "Som FinalColumnName" for at forenkle resultaterne, hvor end de vil blive brugt.

vælg CONCAT(Bruger.Hilsen, Bruger.Efternavn ) som Høflighedsnavn fra ...

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

"Som"-kolonnen Navn er IKKE påkrævet at være et samlet, men ses oftest på den måde.

Med hensyn til MySQL-variablerne... Hvis du lavede en lagret procedure, vil mange mennesker på forhånd erklære, at de indstiller deres standardværdier før resten af ​​proceduren. Du kan gøre dem in-line i en forespørgsel ved blot at indstille og give resultatet en "Alias"-reference. Når du udfører disse variabler, vil select simulere altid at returnere en SINGLE RECORD værdi af værdierne. Det er næsten som en enkelt post, der kan opdateres, brugt i forespørgslen. Du behøver ikke anvende nogen specifikke "Join"-betingelser, da det muligvis ikke har nogen betydning for resten af ​​tabellerne i en forespørgsel... Opretter i bund og grund et kartesisk resultat, men en post mod en anden tabel vil aldrig oprette dubletter under alle omstændigheder, så ingen skader nedstrøms.

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

Hvordan fungerer sqlvars. Tænk på et lineært program... En kommando udføres i den nøjagtige rækkefølge, mens forespørgslen kører. Denne værdi gemmes derefter igen i "SQLVars"-posten, klar til næste gang. Du omtaler det dog ikke som SQLVars.SomeVar eller SQLVars.SomeDate... bare @SomeVar :=someNewValue. Nu, når @var bruges i en forespørgsel, gemmes den også som et "As ColumnName" i resultatsættet. Nogle gange kan dette blot være en pladsholder-beregnet værdi som forberedelse til den næste post. Hver værdi er så direkte tilgængelig for den næste række. Så givet følgende eksempel...

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æg mærke til, hvordan værdien af ​​@SomeVar bruges, da hver kolonne bruger den... Så selv på den samme post er den opdaterede værdi umiddelbart tilgængelig for den næste kolonne... Når det er sagt, se nu på at prøve at bygge et simuleret rekordantal / rangering pr. hver 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

"Order By"-sætningen tvinger resultaterne til at blive returneret i rækkefølge først. Så her returneres registreringerne pr. kunde. Første gang igennem er LastID 0 og kunde-id er sige...5. Da det er anderledes, returnerer det 1 som @SeqNo, SÅ bevarer det det kunde-id i @LastID-feltet for den næste post. Nu, næste post for kunde... Sidste ID er det samme, så det tager @SeqNo (nu =1), og tilføjer 1 til 1 og bliver #2 for den samme kunde... Fortsæt på stien.. .

Med hensyn til at blive bedre til at skrive forespørgsler, så tag et kig på MySQL-tagget og se på nogle af de tunge bidragydere. Se på spørgsmålene og nogle af de komplekse svar, og hvordan problemløsning fungerer. For ikke at sige, at der ikke er andre med lavere omdømmescore, der lige er startet og fuldstændig kompetente, men du vil finde ud af, hvem der giver gode svar og hvorfor. Se også deres historie med de udsendte svar. Jo mere du læser og følger, jo mere får du bedre styr på at skrive mere komplekse forespørgsler.



  1. Tips til migrering fra MySQL-replikering til MySQL Galera Cluster 4.0

  2. Kan ikke oprette forbindelse til lokal MySQL-server gennem socket '/var/lib/mysql/mysql.sock' (2)

  3. hvordan man tilføjer anden i oracle tidsstempel

  4. Ugyldigt datetime-format:1292 Forkert datetime-værdi