Mysql
 sql >> база данни >  >> RDS >> Mysql

Как да оптимизирам заявката, ако таблицата съдържа 10000 записа, използвайки MySQL?

Бих се опитал да опростя това НАПЪЛНО, като поставя тригери в другите ви таблици и просто добавя няколко колони към вашата таблица User_Fans... По една за всеки съответен count(), който се опитвате да получите... от публикации, публикации, харесвания, коментари, PostCommentLikes.

Когато се добави запис към която и да е таблица, просто актуализирайте вашата таблица user_fans, за да добавите 1 към броя... това ще бъде практически мигновено въз основа на идентификатора на ключа на потребителя. Що се отнася до "Харесванията"... Подобно, само при условие, че нещо се задейства като "Харесвам", добавете 1.. Тогава вашата заявка ще бъде директна математика за единичния запис и няма да разчита на НИКАКВИ присъединявания, за да изчисли "претеглена" обща стойност. Тъй като вашата таблица става още по-голяма, заявките също ще стават по-дълги, тъй като имат повече данни за изливане и обобщаване. Преминавате през ВСЕКИ запис на user_fan, който по същество прави заявка за всеки запис от всички останали таблици.

Като се има предвид всичко това, запазвайки таблиците такива, каквито ги имате, бих преструктурирал както следва...

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 към предварителни заявки изпълнява тези заявки ВЕДНЪЖ, след което цялото нещо се присъединява, вместо да бъде ударено като подзаявка за всеки запис. С помощта на COALESCE(), ако няма такива записи в резултатите от таблицата LEFT JOINed, няма да получите NULL стойности, които да объркат изчисленията, така че ги поставих по подразбиране на 000000.

ИЗЯСНЯВАНЕ НА ВАШИТЕ ВЪПРОСИ

Можете да имате произволна QUERY като "AS AliasResult". "As" може също да се използва за опростяване на всякакви дълги имена на таблици за по-лесна четливост. Псевдонимите също могат да използват същата таблица, но като различен псевдоним, за да получите подобно съдържание, но с различна цел.

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

Сега, третата заявка по-горе не е практична да изисква (пълна заявка, която води до псевдоним "PQ", представляващ "PreQuery"). Това може да се направи, ако искате предварително да ограничите определен набор от други сложни условия и искате по-малък набор, ПРЕДИ да извършите допълнително свързване към много други таблици за всички крайни резултати.

Тъй като "FROM" не ТРЯБВА да бъде действителна таблица, но може да бъде заявка сама по себе си, на всяко друго място, използвано в заявката, то трябва да знае как да препраща към този набор от резултати от предварителна заявка.

Освен това, когато се правят заявки за полета, те също могат да бъдат „Като FinalColumnName“, за да се опростят резултатите, където и да се използват.

selectCONCAT( User.Salutation, User.LastName ) като CourtesyNamefrom ...

selectOrder.NonTaxable+ Order.Taxable+ ( Order.Taxable * Order.SalesTaxRate ) като OrderTotalWithTaxfrom ...

Името на колоната „Като“ НЕ е задължително да бъде обобщено, но най-често се разглежда по този начин.

Сега, по отношение на променливите на MySQL... Ако правите съхранена процедура, много хора ще ги декларират предварително, като задават техните стойности по подразбиране преди останалата част от процедурата. Можете да ги направите на линия в заявка, като просто зададете и дадете на този резултат препратка към „псевдоним“. Когато правите тези променливи, изборът ще симулира винаги връщането на стойността на ЕДИН ЗАПИС от стойностите. Това е почти като единичен запис с възможност за актуализиране, използван в заявката. Не е необходимо да прилагате никакви специфични условия за присъединяване, тъй като може да няма никакво отношение към останалите таблици в заявката... По същество създава декартов резултат, но един запис срещу всяка друга таблица никога няма да създаде все пак се дублират, така че няма повреди надолу по веригата.

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

Сега, как работят sqlvars. Помислете за линейна програма... Една команда се изпълнява в точната последователност, докато се изпълнява заявката. След това тази стойност се съхранява отново в записа "SQLVars", готов за следващия път. Въпреки това, вие не го посочвате като SQLVars.SomeVar или SQLVars.SomeDate... просто @SomeVar :=someNewValue. Сега, когато @var се използва в заявка, той също се съхранява като "Като ColumnName" в набора от резултати. Понякога това може да бъде само задържаща място, изчислена стойност при подготовката на следващия запис. След това всяка стойност е директно достъпна за следващия ред. И така, като се има предвид следната извадка...

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

Забележете как стойността на @SomeVar се използва, тъй като всяка колона я използва... Така че дори в същия запис, актуализираната стойност е незабавно достъпна за следващата колона... Въпреки това, сега погледнете как се опитвате да изградите симулиран брой записи / класиране за всеки клиент...

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

Клаузата "Поръчай по" принуждава резултатите да се връщат последователно първо. И така, тук записите на клиент се връщат. За първи път LastID е 0, а клиентският идентификатор е да кажем...5. Тъй като е различен, той връща 1 като @SeqNo, ТОГАВА запазва този клиентски идентификатор в полето @LastID за следващия запис. Сега следващият запис за клиента... Последният идентификатор е същият, така че приема @SeqNo (сега =1) и добавя 1 към 1 и става #2 за същия клиент... Продължете по пътя.. .

Що се отнася до подобряването на писането на заявки, погледнете маркера MySQL и вижте някои от най-големите участници. Разгледайте въпросите и някои от сложните отговори и как работи решаването на проблеми. Да не кажа, че няма други с по-ниски резултати за репутация, които тепърва започват и са напълно компетентни, но ще откриете кой дава добри отговори и защо. Вижте и тяхната история на публикуваните отговори. Колкото повече четете и следвате, толкова повече ще се справите с писането на по-сложни заявки.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. премахване на информация от таблицата на mysql, когато потребителят затвори своя браузър

  2. Получаване на PHP PDO връзка от mysql_connect()?

  3. В MySQL възможно ли е да се върнат повече от 1024 знака от GROUP_CONCAT

  4. Вмъкване на първичен ключ за автоматично увеличение в съществуващата таблица

  5. Подреждане по подразбиране в MySQL (ALTER TABLE ... ORDER BY ...;)