sql >> Databasteknik >  >> RDS >> Mysql

Hur optimerar man frågan om tabellen innehåller 10 000 poster med MySQL?

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.



  1. Vilket är snabbare:flera enkla INSERT eller en INSERT med flera rader?

  2. Lär dig hur du använder SQL SELECT med exempel

  3. Python MySQLdb / MySQL INSERT IGNORE &Kontrollera om ignoreras

  4. Hur man listar de föråldrade funktionerna i en SQL Server-instans med T-SQL