Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jak zoptymalizować zapytanie, jeśli tabela zawiera 10000 wpisów przy użyciu MySQL?

Spróbowałbym uprościć to CAŁKOWICIE, umieszczając wyzwalacze na innych twoich tabelach i po prostu dodając kilka kolumn do tabeli User_Fans... Po jednej dla każdej odpowiedniej count(), którą próbujesz uzyskać... z postów, postów, polubień, komentarzy, Dodaj komentarz lubi.

Kiedy rekord zostanie dodany do dowolnej tabeli, po prostu zaktualizuj swoją tabelę user_fans, aby dodać 1 do liczby... i tak będzie to praktycznie natychmiastowe na podstawie identyfikatora klucza użytkownika. Jeśli chodzi o „LUBIE”... Podobnie, tylko pod warunkiem, że coś zostanie wywołane jako „Lubię to”, dodaj 1. Wtedy zapytanie będzie bezpośrednią matematyką na pojedynczym rekordzie i nie będzie polegać na JAKICHKOLWIEK złączeniach w celu obliczenia „ważona” wartość całkowita. W miarę jak Twoja tabela staje się jeszcze większa, zapytania również stają się dłuższe, ponieważ mają więcej danych do przelania i agregacji. Przechodzisz przez KAŻDY rekord user_fan, który w istocie odpytuje każdy rekord ze wszystkich innych tabel.

Biorąc to wszystko pod uwagę, zachowując tabele tak, jak je masz, zmieniłbym strukturę w następujący sposób...

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 do zapytań wstępnych uruchamia te zapytania RAZ, a następnie całość jest łączona zamiast trafienia jako podzapytanie dla każdego rekordu. Używając funkcji COALESCE(), jeśli nie ma takich wpisów w wynikach tabeli LEFT JOINed, nie dostaniesz trafienia z wartościami NULL zakłócającymi obliczenia, więc ustawiłem je domyślnie na 000000.

WYJAŚNIENIE TWOICH PYTAŃ

Możesz mieć dowolne QUERY jako „AS AliasResult”. „As” można również użyć do uproszczenia długich nazw tabel w celu zwiększenia czytelności. Aliasy mogą również używać tej samej tabeli, ale jako innego aliasu, aby uzyskać podobną zawartość, ale w innym celu.

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

Teraz trzecie zapytanie powyżej nie jest praktyczne i wymaga (pełnego zapytania, którego rezultatem jest alias "PQ" reprezentujący "PreQuery" ). Można to zrobić, jeśli chcesz wstępnie ograniczyć pewien zestaw innych złożonych warunków i chcesz mieć mniejszy zestaw PRZED wykonaniem dodatkowych złączeń do wielu innych tabel dla wszystkich wyników końcowych.

Ponieważ "FROM" NIE MUSI być rzeczywistą tabelą, ale może być zapytaniem samym w sobie, w dowolnym innym miejscu zapytania, musi wiedzieć, jak odwołać się do tego zbioru wyników wstępnego zapytania.

Ponadto, podczas wykonywania zapytań w polach, one również mogą być „jako nazwakolumny końcowej”, aby uprościć wyniki tam, gdzie będą również używane.

selectCONCAT( Użytkownik.Zwrot grzecznościowy, Użytkownik.Nazwisko ) as CourtesyNamefrom ...

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

Nazwa kolumny „Jako” NIE jest wymagana jako agregacja, ale najczęściej jest tak postrzegana.

Teraz, w odniesieniu do zmiennych MySQL... Jeśli wykonywałeś procedurę składowaną, wiele osób zadeklaruje, że ustawiają one domyślne wartości przed resztą procedury. Możesz je wykonać w zapytaniu, ustawiając i nadając wynikowi odwołanie „Alias”. Podczas wykonywania tych zmiennych, select będzie symulować zawsze zwracanie wartości POJEDYNCZEGO REKORDU. To prawie jak pojedynczy rekord z możliwością aktualizacji, używany w zapytaniu. Nie musisz stosować żadnych konkretnych warunków „Połącz”, ponieważ może to nie mieć żadnego wpływu na pozostałe tabele w zapytaniu... Zasadniczo tworzy wynik kartezjański, ale jeden rekord z dowolną inną tabelą nigdy nie zostanie utworzony i tak powiela się, więc nie ma żadnych uszkodzeń.

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

Teraz, jak działają sqlvary. Pomyśl o programie liniowym... Jedno polecenie jest wykonywane w dokładnej kolejności w trakcie wykonywania zapytania. Ta wartość jest następnie ponownie przechowywana w rekordzie „SQLVars”, gotowa do następnego przejścia. Jednak nie odwołujesz się do niego jako SQLVars.SomeVar lub SQLVars.SomeDate... tylko @SomeVar :=someNewValue. Teraz, gdy @var jest używany w zapytaniu, jest również przechowywany jako „As ColumnName” w zestawie wyników. Czasami może to być tylko zastępcza wartość obliczona podczas przygotowywania następnego rekordu. Każda wartość jest wtedy bezpośrednio dostępna dla następnego wiersza. Tak więc, biorąc pod uwagę następującą próbkę...

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

Zwróć uwagę, w jaki sposób używana jest wartość @SomeVar, ponieważ używa jej każda kolumna... Więc nawet w tym samym rekordzie zaktualizowana wartość jest natychmiast dostępna dla następnej kolumny... To powiedziawszy, teraz spójrz na próbę zbudowania symulowanej liczby rekordów / ranking na każdego klienta...

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

Klauzula „Order By” wymusza najpierw zwrócenie wyników w kolejności. Tak więc tutaj zwracane są rekordy na klienta. Za pierwszym razem LastID to 0, a identyfikator klienta to...5. Ponieważ jest inny, zwraca 1 jako @SeqNo, WTEDY zachowuje ten identyfikator klienta w polu @LastID dla następnego rekordu. Teraz następny rekord dla klienta... Ostatni identyfikator jest taki sam, więc przyjmuje @SeqNo (teraz =1), dodaje 1 do 1 i staje się numerem 2 dla tego samego klienta... Kontynuuj ścieżką... .

Jeśli chodzi o poprawę umiejętności pisania zapytań, spójrz na znacznik MySQL i przyjrzyj się niektórym częstym współpracownikom. Przyjrzyj się pytaniom i niektórym złożonym odpowiedziom oraz temu, jak działa rozwiązywanie problemów. Nie znaczy to, że nie ma innych osób o niższych wynikach reputacji, które dopiero zaczynają i są całkowicie kompetentne, ale przekonasz się, kto udziela dobrych odpowiedzi i dlaczego. Spójrz też na ich historię opublikowanych odpowiedzi. Im więcej czytasz i śledzisz, tym lepiej radzisz sobie z pisaniem bardziej złożonych zapytań.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. spróbuj zmienić katalog dziennika bin:nie znaleziono mysql-bin.index (Errcode:13)

  2. Jak porównywać wydajność Moodle?

  3. SQL Inner Join – Jak połączyć 3 tabele w SQL i MySQL

  4. Zrozumienie dziennika audytu ProxySQL

  5. Użyte instrukcje SELECT mają różną liczbę kolumn (REDUX!!)