web-dev-qa-db-ja.com

JOIN条件とWHERE条件の実行に違いはありますか?

これら2つのサンプルクエリの間にパフォーマンスの違いはありますか?

クエリ1:

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y'

クエリ2;

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
   and b.tag = 'Y'

唯一の違いは補足条件の配置です。 1つ目はWHERE句を使用し、2つ目はON句に条件を追加します。

Teradataシステムでこれらのクエリを実行すると、Explainプランは同じになり、JOINステップはそれぞれの場合の追加条件を示します。ただし、MySQLに関する this SO question では、結合の作成後にWHERE処理が発生するため、2番目のスタイルが推奨されるという回答の1つ。

このようなクエリをコーディングする際に従うべき一般的なルールはありますか?それは明らかに私のデータベースに影響を与えないので、プラットフォームに依存している必要があると思いますが、おそらくそれはTeradataの単なる機能です。そして、それがisプラットフォームに依存している場合、いくつかのドキュメント参照を取得してください。何を探すべきか本当にわからない。

17
BellevueBob

本の第9章(パーサーおよびオプティマイザー)のページ172によれば、 Sasha PachevによるMySQLの内部の理解

Understanding MySQL Internals

以下は、次のタスクとしてのクエリの評価の内訳です。

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

同じページで、次のように書かれています。

MySQLオプティマイザの用語では、すべてのクエリは一連の結合です。ここでは、joinという用語がSQLコマンドよりも広く使用されています。 1つのテーブルのみに対するクエリは、縮退結合です。通常、1つのテーブルからレコードを読み取ることは結合とは考えていませんが、従来の結合で使用されるのと同じ構造とアルゴリズムは、1つのテーブルのみでクエリを解決するために完全に機能します。

エピローグ

存在するキー、データの量、およびクエリの式のため、MySQL結合は時々私たち自身のために(または戻ってくるために)何かを行い、予期しない結果を思い付き、すぐに説明することができません。

以前にこの癖について書いた

これは、MySQLクエリオプティマイザーがクエリの評価中に特定のキーを破棄する可能性があるためです。

@Philのコメントは、この回答の投稿方法を確認するのに役立ちます(@Philのコメントに+1)

MySQLのクエリオプティマイザーは原始的であるため、@ ypercubeのコメント(これについても+1)は私の投稿のコンパクトバージョンです。残念ながら、それは外部のストレージエンジンを扱っているためでなければなりません。

結論

あなたの実際の質問に関しては、MySQL Query Optimizerは、完了時に各クエリのパフォーマンスメトリックを決定します

  • 行を数える
  • キーの選択
  • 断続的な結果セットのマッサージ
  • そうそう、実際のJOINを行う

おそらく、クエリを書き換える(リファクタリングする)ことにより、実行の順序を強制する必要があります。

ここにあなたが与えた最初のクエリがあります

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y';

最初にWHEREを評価するように書き直してください

select count(*)
from   table1 a
join   (select key_col from table2 where tag='Y') b
on     b.key_col=a.key_col;

それは間違いなくEXPLAIN計画を変更します。それはより良いまたはより悪い結果を生み出す可能性があります。

このテクニックを適用したStackOverflowで質問に一度回答しました。EXPLAINは恐ろしいものでしたが、パフォーマンスはダイナマイトでした。正しいインデックスが存在し、サブクエリでLIMITが使用されているためにのみ機能しました

株価と同様に、クエリについてそれを表現しようとすると、制限が適用され、結果が異なる場合があり、過去のパフォーマンスは将来の結果を示すものではありません。

14
RolandoMySQLDBA

Oracleの場合、mySQLには長い説明があったため、オプティマイザを活用する2つの高レベルの方法があります。

まず、ルールベースの最適化(またはRBO)です。 Oracleには15の基本的なルールがあり、構文解析する各クエリは、設定された順序で従おうとします。ルール1から最適化されたクエリを生成できない場合は、ルール2に進み、ルール15に達するまで続行します。

詳細: https://docs.Oracle.com/cd/B10500_01/server.920/a96533/rbo.htm

これらは、Cost Based Optimizer(別名CBO)に変換されていない11.1以下のOracle RDBMSカーネルに影響します。 Oracle 11.2以降ではCBOオプティマイザーが必要ですが、ユーザーが希望する場合は、特定のSQL IDを古いRBOメソッドで強制的に最適化できます。

代わりに、Oracle 11.1+のCBOは、同じSQL IDに対していくつかの実行プランを作成し、全体の予想コストが最も少ないものを実行します。 RBOの多くのロジックを活用しますが、テーブル統計を分析して、エンドユーザーにデータを提供するためにDBが実行する必要がある各操作の動的実行計画コストを作成します。非常に大きなテーブルで全テーブルスキャンを実行すると、非常にコストがかかります。 10行のテーブルで全テーブルスキャンを実行するのが安価です。 RBOでは、これらは同等の操作と見なされていました。

詳細: https://Oracle-base.com/articles/misc/cost-based-optimizer-and-database-statistics

特定のクエリの例の場合:Oracleは情報を解析して異なる実行プランを作成する可能性が高いため、一方が他方よりも技術的に優れています。ただし、これはごくわずかな違いです。注目に値するのは、Oracle RBOとCBOの両方がより少ない条件で結合で実行され、結合から作成された一時テーブルから特定の列をフィルターで除外するため、クエリ1を増やしたいということです。

1
JB-Learner

2つのクエリがあり、それらが同等であると思われる場合、次のことが起こります。

  1. 両方のクエリの実行プランは同じです。それは問題なく、それが私たちが期待することです。それがクエリの最適な実行計画であることを期待しましょう。
  2. 異なる実行計画があります。ここには2つのサブケースがあります。

    2.1クエリには異なる実行プランがありますが、どちらのプランも同等に良好に機能します。それも結構です。同等のクエリに対して同じプランを生成する必要はありません。しかし、パフォーマンスは同等でなければなりません。そして、私たちはそれが可能な限り最高であることを願っています。

    2.2クエリには異なる実行プランがあり、1つのプランが他のプランよりも優れています。ここでもサブケースがあります:

    2.2.1クエリは同等ではないため、計画は異なります。したがって、それらが本当に同等であるかどうかを慎重に確認してください。あなたの場合、それらは本当に同等です。

    2.2.2プランは異なりますが、クエリは同等です。これは、オプティマイザが十分に成熟していないことを意味します。完璧なオプティマイザのある完璧な世界では、これは起こらないはずです。つまり、プラットフォームに依存するため、プラットフォーム固有のドキュメントを調べて、これが発生する理由を見つける必要があります。

    2.2.3計画は異なり、クエリは同等で、データベースソフトウェアにバグがあります。

1
miracle173