sql >> データベース >  >> RDS >> Mysql

MySQLを使用してテーブルに10000エントリが含まれている場合、クエリを最適化するにはどうすればよいですか?

    他のテーブルにトリガーを配置し、User_Fansテーブルにいくつかの列を追加することでこの完全な単純化を試みます...取得しようとしているそれぞれのcount()ごとに1つ... Posts、PostLikes、PostComments、 PostCommentLikes。

    レコードがどちらのテーブルに追加された場合でも、user_fansテーブルを更新してカウントに1を追加するだけです...とにかく、ユーザーのキーIDに基づいて事実上瞬時になります。 「LIKES」について...同様に、何かが「Like」としてトリガーされるという条件の下でのみ、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
    

    プレクエリへのLEFTJOINは、これらのクエリを1回実行します。その後、すべてのレコードのサブクエリとしてヒットされるのではなく、すべてが結合されます。 COALESCE()を使用すると、LEFT JOINedテーブルの結果にそのようなエントリがない場合、計算を台無しにするNULL値に見舞われることはないため、デフォルトで000000に設定しました。

    質問の明確化

    「ASAliasResult」として任意のQUERYを設定できます。 「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 ...
    

    さて、上記の3番目のクエリは、(「PreQuery」を表すエイリアス「PQ」を生成する完全なクエリ)を必要とするのは実用的ではありません。これは、他の複雑な条件の特定のセットを事前に制限し、すべての最終結果のために他の多くのテーブルに追加の結合を行う前に、より小さなセットが必要な場合に実行できます。

    「FROM」は実際のテーブルである必要はありませんが、それ自体がクエリである可能性があるため、クエリで使用される他の場所では、このクエリ前の結果セットを参照する方法を知っている必要があります。

    また、フィールドをクエリするときは、フィールドも「As FinalColumnName」にして、結果を使用する場所に単純化することができます。

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

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

    「As」columnNameは集計である必要はありませんが、最も一般的にはそのように表示されます。

    さて、MySQL変数に関して...ストアドプロシージャを実行している場合、多くの人は、残りのプロシージャの前にデフォルト値を設定することを事前に宣言します。その結果に「エイリアス」参照を設定して指定するだけで、クエリでインラインでそれらを実行できます。これらの変数を実行する場合、selectは常にSINGLERECORDに相当する値を返すことをシミュレートします。これは、クエリ内で使用される更新可能な単一のレコードとほとんど同じです。クエリ内の残りのテーブルとは関係がない可能性があるため、特定の「結合」条件を適用する必要はありません...本質的に、デカルト結果を作成しますが、他のテーブルに対する1つのレコードは作成されません。とにかく複製するので、下流に損傷はありません。

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

    ここで、sqlvarsがどのように機能するかを説明します。線形計画法を考えてみてください...クエリの実行時に、1つのコマンドが正確な順序で実行されます。その後、その値は「SQLVars」レコードに再保存され、次回の準備が整います。ただし、SQLVars.SomeVarまたはSQLVars.SomeDate ...として参照するのではなく、@ SomeVar:=someNewValueとして参照します。これで、@ varがクエリで使用されると、結果セットに「AsColumnName」としても保存されます。場合によっては、これは次のレコードの準備でのプレースホルダーの計算値にすぎないことがあります。各値は、次の行で直接使用できます。したがって、次のサンプルが与えられます...

    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
    

    「OrderBy」句は、結果を最初に順番に返すように強制します。したがって、ここでは、顧客ごとのレコードが返されます。初めての場合、LastIDは0で、顧客IDは次のようになります...5。異なるため、@ SeqNoとして1を返し、その顧客IDを次のレコードの@LastIDフィールドに保持します。さて、顧客の次のレコード...最後のIDは同じなので、@ SeqNo(現在=1)を取り、1を1に加算して、同じ顧客の#2になります...パスを続行します。 。

    クエリの記述を上手に行うために、MySQLタグを見て、大きな貢献者のいくつかを見てください。質問といくつかの複雑な答え、および問題解決がどのように機能するかを調べてください。始めたばかりで完全に有能な評判スコアの低い人がいないことは言うまでもありませんが、誰が良い答えを出し、その理由はわかります。投稿された回答の履歴も見てください。読んで従うほど、より複雑なクエリを書く際の扱いが良くなります。



    1. SQLServerフェールオーバークラスター内のシステムデータベースの移動

    2. SQLServerのパフォーマンスを容易にする

    3. Hibernateを使用してPostgreSQL配列をマップする方法

    4. MySQL:FROM句で更新するターゲットテーブルの「タスク」を指定することはできません