web-dev-qa-db-ja.com

誰かがmysqlで2つのビューを結合するのが遅いのはなぜか説明できますか?

これが私が昨日尋ねた質問です- https://stackoverflow.com/questions/22180727/left-joining-two-views-is-slow

私は助けになった良い答えを得ましたが、LEFT JOINが検索よりもはるかに遅い理由がわかりません。 LEFT JOINは16秒でした-私のテーブルは少なくとも90%最適化されていると確信しています-ルックアップを実行すると、それはわずか.14秒です。テーブルを左に結合した場合、これは遅くはないので、なぜビューなのでしょうか?

7
LOSTinDB

ビューの MySQLドキュメントによると

ビュー(更新可能なビューを含む)はMySQL Server 5.6で使用できます。ビューは、呼び出されたときに結果セットを生成するストアドクエリです。ビューは仮想テーブルとして機能します。

ビューについて最初に理解する必要があるのは、ビューが結果セットを生成することです。ビューから呼び出されたクエリから発生する結果セットは、オンデマンドで作成されるため、仮想テーブルです。結果セットをすぐにインデックス化するために後で呼び出すことができるDDLはありません。すべての意図と目的で、結果セットはインデックスのないテーブルです。実際には、実行していたLEFT JOINは基本的に、何らかのフィルタリングを施したデカルト積です。

2つのビューのJOINをより詳細に確認するために、MySQLがJOINとWHEREを評価するために使用する内部メカニズムを説明する昨年作成した投稿を参照します( JOIN条件とWHERE条件? )。 MySQL内部の理解 (ページ172)で公開されているメカニズムを紹介します。

  • テーブルからレコードを取得するために使用できるキーを決定し、各テーブルに最適なキーを選択します。
  • 各テーブルについて、テーブルスキャンがキーの読み取りよりも優れているかどうかを判断します。キー値に一致するレコードが多数ある場合、キーの利点が減り、テーブルスキャンが高速になります。
  • クエリに複数のテーブルが存在する場合に、テーブルを結合する順序を決定します。
  • WHERE句を書き換えて不要なコードを排除し、不要な計算を減らし、制約を可能な限り変更して、キーを使用する方法を開きます。
  • 未使用のテーブルを結合から削除します。
  • ORDER BYおよびGROUP BYにキーを使用できるかどうかを確認します。
  • サブクエリを簡略化し、結果をキャッシュできる範囲を決定してください。
  • ビューのマージ(ビュー参照をマクロとして展開)

OK、インデックスを使用する必要があるようです。ただし、よく見てください。 WordのViewTableに置き換えた場合、メカニズムの実行がどうなるか見てください。

メカニズムが変更されました

  • viewsからレコードを取得するために使用できるキーを決定し、それぞれに最適なキーを選択しますview
  • viewごとに、キーの読み取りよりもviewスキャンの方が優れているかどうかを判断します。キー値に一致するレコードが多数ある場合、キーの利点が減り、viewスキャンが高速になります。
  • クエリに複数のviewsが存在する場合にviewsを結合する順序を決定します。
  • WHERE句を書き換えて不要なコードを排除し、不要な計算を減らし、制約を可能な限り変更して、キーを使用する方法を開きます。
  • 未使用のviewsを結合から削除します。
  • ORDER BYおよびGROUP BYにキーを使用できるかどうかを確認します。
  • サブクエリを簡略化し、結果をキャッシュできる範囲を決定してください。
  • ビューのマージ(ビュー参照をマクロとして展開)

すべてのテーブル(ビュー)にはインデックスがありません。したがって、JOINを実行すると、仮想テーブル、一時テーブル、またはインデックスのないテーブルでの作業は実際には不明確になります。使用されるキーはJOIN操作のためだけのものであり、物事をより速く検索するためのものではありません。

クエリ を、2014イエローページと2013イエローページの2つの電話帳を取得するものと考えてください。各イエローページの本には、住宅電話番号のホワイトページが含まれています。

  • 2012年後半、データベーステーブルが2013イエローページの生成に使用されました。
  • 2013年中
    • 人々は電話番号を変えた
    • 人々は新しい電話番号を受け取りました
    • 人々は電話番号を落とし、携帯電話に切り替えた
  • 2013年後半、データベーステーブルが2014年のイエローページの生成に使用されました。

明らかに、2つの電話帳には違いがあります。データベーステーブルのJOINを実行して2013年と2014年の違いを理解しても問題はありません。

2つの電話帳を手動でマージして違いを見つけることを想像してみてください。正気に聞こえませんか?それにもかかわらず、これは、2つのビューに参加するときにmysqldに要求することとまったく同じです。実際のテーブルを結合するのではなく、そこから便乗するインデックスがないことを覚えておいてください。

では、実際のクエリを振り返ってみましょう。

SELECT DISTINCT
viewA.TRID, 
viewA.hits,
viewA.department,
viewA.admin,
viewA.publisher,
viewA.employee,
viewA.logincount,
viewA.registrationdate,
viewA.firstlogin,
viewA.lastlogin,
viewA.`month`,
viewA.`year`,
viewA.businesscategory,
viewA.mail,
viewA.givenname,
viewA.sn,
viewA.departmentnumber,
viewA.sa_title,
viewA.title,
viewA.supemail,
viewA.regionname
FROM
viewA
LEFT JOIN viewB ON viewA.TRID = viewB.TRID
WHERE viewB.TRID IS NULL 

仮想テーブル(インデックスのないテーブル)viewAを使用しており、それを別の仮想テーブルviewBに結合しています。断続的に生成される一時テーブルは、viewAと同じ大きさになります。次に、大きな一時テーブルで内部ソートを実行して、それを区別します。

エピローグ

ビューの結果セットの一時的でインデックスなしの性質に沿って、JOINを評価する内部メカニズムを考えると、元のクエリ(2つのビューのLEFT JOIN)は桁違いの実行時間を取得しているはずです。同時に、 StackOverflowから取得した回答 は、今説明したのと同じJOINアルゴリズムを考えると、適切に機能するはずです。

私が投稿したばかりの悲惨な詳細が、理由についてのあなたの質問に答えることを願っています。

10
RolandoMySQLDBA

EXPLAIN EXTENDED [select query] その後 SHOW WARNINGSは、ビューの書き換えられた形式を表示します。ここから、パフォーマンス特性を分析する方が簡単です。

視力検査クエリは、一般的に最適化が容易ではありません。

1
Morgan Tocker