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

MySQLにビュークエリにINDEXを使用させるにはどうすればよいですか?

    MySQLにビュークエリにインデックスを使用させるにはどうすればよいですか?簡単に言えば、MySQLが使用できるインデックスを提供してください。

    この場合、最適なインデックスは「カバーする」インデックスである可能性があります。

    ... ON highscores (player, happened_in, score)
    

    MySQLがそのインデックスを使用する可能性が高く、EXPLAINには次のように表示されます: "Using index" WHERE player =24による (インデックスの先頭の列の等式述語。 GROUP BYhappened_id (インデックスの2番目の列)、MySQLがインデックスを使用してそれを最適化し、ソート操作を回避できるようにする場合があります。 スコアを含む インデックスの列を使用すると、インデックスによって参照されるデータページにアクセス(ルックアップ)することなく、クエリをインデックスから完全に満たすことができます。

    それが簡単な答えです。より長い答えは、MySQLが happened_idの先頭の列を持つインデックスを使用する可能性は非常に低いということです。 ビュークエリの場合。

    ビューによってパフォーマンスの問題が発生する理由

    MySQLビューで発生する問題の1つは、MySQLが述語を外部クエリからビュークエリに「プッシュ」しないことです。

    外部クエリは、 WHEREoccured_in =2006を指定します 。 MySQLオプティマイザは、内部の「ビュークエリ」を実行するときに述語を考慮しません。ビューに対するそのクエリは、外部クエリの前に個別に実行されます。そのクエリの実行からの結果セットは「マテリアライズ」されます。つまり、結果は中間のMyISAMテーブルとして保存されます。 (MySQLはこれを「派生テーブル」と呼んでおり、MysQLが実行する操作を理解している場合、それらが使用する名前は理にかなっています。)

    肝心なのは、 happened_inで定義したインデックスです。 ビュー定義を形成するクエリを実行するときにMySQLによって使用されていません。

    中間の「派生テーブル」が作成された後、その「派生テーブル」を行ソースとして使用して、外部クエリが実行されます。 happened_in =2006 が実行されるのは、その外部クエリが実行されるときです。 述語が評価されます。

    ビュークエリのすべての行が保存されていることに注意してください。これは(あなたの場合) happened_inのすべての値の行です。 、外部クエリで等式述語を指定したものだけではありません。

    ビュークエリの処理方法は「予期しない」ものもあります。これが、他のリレーショナルデータベースによるビュークエリの処理方法と比較して、MySQLで「ビュー」を使用するとパフォーマンスの問題が発生する可能性がある理由の1つです。

    >

    適切なカバーインデックスを使用してビュークエリのパフォーマンスを向上させる

    ビュー定義とクエリを考えると、得られる最善の方法は、ビュークエリの「インデックスの使用」アクセス方法です。これを取得するには、カバーするインデックスが必要です。例:

    ... ON highscores (player, happened_in, score).
    

    これは、既存のビュー定義と既存のクエリにとって最も有益なインデックス(パフォーマンスの観点から)である可能性があります。 プレーヤー ビュークエリのその列に等式述語があるため、columnが先頭の列です。 happened_in 次の列は、その列にGROUP BY操作があり、MySQLがこのインデックスを使用してGROUPBY操作を最適化できるようにするためです。 スコアも含まれています これは、クエリで参照される他の唯一の列であるためです。これにより、インデックスは「カバーする」インデックスになります。これは、MySQLが、基になるテーブルのページにアクセスする必要なしに、インデックスページから直接そのクエリを満たすことができるためです。そして、それは、「ファイルソートの使用」なしで「インデックスの使用」というクエリプランから抜け出すのと同じくらい良いことです。

    パフォーマンスを派生テーブルのないスタンドアロンクエリと比較します

    クエリの実行プランをビューと同等のスタンドアロンクエリと比較できます:

    SELECT player
         , MAX(score) AS highest_score
         , happened_in
     FROM highscores
    WHERE player = 24
      AND happened_in = 2006
    GROUP
       BY player
        , happened_in
    

    スタンドアロンクエリは、カバーリングインデックスを利用することもできます。

    ... ON highscores (player, happened_in, score)
    

    ただし、中間のMyISAMテーブルを具体化する必要はありません。

    上記のいずれかが、あなたが尋ねていた質問に対する直接の答えを提供するかどうかはわかりません。

    Q:ビュークエリにINDEXを使用するようにMySQLを取得するにはどうすればよいですか?

    A:ビュークエリが使用できる適切なINDEXを定義します。

    簡単な答えは、「カバーインデックス」を提供することです(インデックスには、ビュークエリで参照されるすべての列が含まれます)。そのインデックスの先頭の列は、等式述語で参照される列である必要があります(この場合、列 player player =24 があるため、先頭の列になります クエリ内の述語。また、GROUP BYで参照される列は、インデックスの先頭の列である必要があります。これにより、MySQLは GROUP BYを最適化できます。 並べ替え操作ではなく、インデックスを使用する操作。

    ここで重要な点は、ビュークエリは基本的にスタンドアロンクエリであるということです。そのクエリの結果は、中間の「派生」テーブル(ビューに対するクエリが実行されたときに作成されるMyISAMテーブル)に格納されます。

    MySQLでビューを使用することは必ずしも「悪い考え」ではありませんが、MySQL内でビューを使用することを選択した人は、MySQLがそれらのビューを参照するクエリを処理する方法に注意することを強くお勧めします。また、MySQLがビュークエリを処理する方法は、ビュークエリが他のデータベース(Oracle、SQL Serverなど)によって処理される方法とは(大幅に)異なります。



    1. Postgresの配列列の各要素に関数を適用するにはどうすればよいですか?

    2. テーブルOracleを動的にピボットする

    3. SQL Server 2005でテーブル内の複数の列の合計を見つける方法は?

    4. MySQLサーバーでのMariaDBフラッシュバックの使用