web-dev-qa-db-ja.com

1つの大きなクエリまたは多くの小さなクエリのどちらが高速ですか。

私はさまざまな会社で働いており、それらの一部は、すべての「親戚」とテーブルを結合するビューを持つことを好むことに気づきました。しかし、アプリケーションでは時々、1列のみを使用する必要があります。

では、単純な選択を行ってから、システムコードでそれらを「結合」する方が速いでしょうか?

システムは、php、Java、asp、データベースに接続する任意の言語です。

したがって、問題は、サーバー側(php、Java、asp、Ruby、python ...)からデータベースへの高速なもので、必要なすべてを取得する1つのクエリを実行するか、サーバー側からデータベースに移動して、一度に1つのテーブルからのみ列を取得するクエリ?

76
sudo.ie

あなたの質問に対処するのは、主題の分解の結合です。

本の Page 209によると

High Performance MySQL

複数テーブル結合の代わりに複数の単一テーブルクエリを実行して、アプリケーションで結合を実行することにより、結合を分解できます。たとえば、次の1つのクエリの代わりに:

_SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id = tag.id
JOIN post ON tag_post.post_id = post.id
WHERE tag.tag = 'mysql';
_

次のクエリを実行できます。

_SELECT * FROM tag WHERE tag = 'mysql';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN (123,456,567,9098,8904);
_

いったいなぜこれを行うのですか?見返りに何も返さずにクエリの数を増やしたので、一見無駄に見えます。ただし、このような再構築により、実際にパフォーマンスが大幅に向上します。

  • キャッシングはより効率的です。多くのアプリケーションは、テーブルに直接マップする「オブジェクト」をキャッシュします。この例では、タグmysqlのオブジェクトがすでにキャッシュされている場合、アプリケーションは最初のクエリをスキップします。 IDが123、567、または908の投稿がキャッシュにある場合は、それらをIN()リストから削除できます。クエリキャッシュもこの戦略の恩恵を受ける可能性があります。 1つのテーブルのみが頻繁に変更される場合、結合を分解すると、キャッシュの無効化の数を減らすことができます。
  • クエリを個別に実行すると、ロックの競合が減少する場合があります
  • アプリケーションで結合を行うと、テーブルを異なるサーバーに配置することで、データベースのスケーリングが容易になります。
  • クエリ自体はより効率的です。この例では、結合の代わりにIN()リストを使用すると、MySQLが結合で可能な場合よりも行IDをソートし、行をより最適に取得できるようになります。
  • 冗長な行アクセスを減らすことができます。アプリケーションで結合を実行することは、各行を1回だけ取得することを意味します。一方、クエリでの結合は、本質的に非正規化であり、同じデータに繰り返しアクセスする可能性があります。同じ理由で、このような再構築により、ネットワークトラフィックの合計とメモリ使用量も減少する可能性があります。
  • ある程度、この手法は、MySQLが結合の実行に使用するネストされたループアルゴリズムではなく、ハッシュ結合を手動で実装していると見なすことができます。ハッシュ結合はより効率的かもしれません。

その結果、以前のクエリから大量のデータをキャッシュして再利用したり、複数のサーバーにデータを分散したり、結合をIN()リストに置き換えたり、結合が参照したりすると、アプリケーションでの結合の実行がより効率的になります。同じテーブルに複数回。

観察

InnoDBはクエリキャッシュをクロスチェックするときに少し強引なので、最初の箇条書きが好きです。

最後の箇条書きに関しては、2013年3月11日に投稿を書きました( JOIN条件とWHERE条件の実行に違いがありますか? )。ネストされたループアルゴリズムについて説明しています。それを読んだ後、結合分解がいかに優れているかがわかります。

book からの他のすべてのポイントについては、開発者は実際に最終的なパフォーマンスとしてパフォーマンスを探します。高速ディスクの使用、より多くのCPU /コアの取得、ストレージエンジンの調整、構成ファイルの調整など、パフォーマンスを向上させるために(アプリケーション以外の)外部手段に依存している人もいます。他の人は座屈してより良いコードを書きます。ストアドプロシージャですべてのビジネスインテリジェンスのコーディングに頼っても、結合分解を適用しない場合もあります( データベースレイヤーにアプリケーションロジックを配置することに対する、またはそれに対する引数は何ですか? 投稿)。それはすべて、各デベロッパーショップの文化と許容度次第です。

一部はパフォーマンスに満足し、もはやコードに触れないかもしれません。他の人たちは、彼らが参加作曲を試みた場合に得ることができる大きな利点があることに気づいていないだけです。

喜んでいる開発者のために...

試してみる !!!

73
RolandoMySQLDBA

Postgres(およびおそらく同様の範囲のRDBMS、より少ない範囲のMySQL)では、少ないクエリはほとんど常にずっと速くなります

複数のクエリの解析と計画のオーバーヘッドは、ほとんどの場合、可能な利益よりもすでに多くなっています。

クライアントで行われる追加の作業については言わず、結果を組み合わせます。これは通常、はるかに遅いです。 RDBMSは、この種のタスクに特化しており、操作は元のデータ型に基づいています。 textにキャストしたり、中間結果に戻したり、クライアントのネイティブタイプに変換したりする必要はありません。これにより、結果の正確性が低下する可能性があります。浮動小数点数について考える...

また、DBサーバーとクライアントの間でより多くのデータを転送します。これは、価値のあるハンドでは無視できるか、大きな違いを生む可能性があります。

複数のクエリがデータベースサーバーへの複数のラウンドトリップを意味する場合は、ネットワークレイテンシとトランザクションオーバーヘッド、さらには接続オーバーヘッドさえも複数回収集します。大きな、大きな損失。

設定によっては、ネットワークの待ち時間だけで、他のすべての待ち時間よりも桁違いに長くかかる場合があります。

SOに関する関連質問:

トランザクションは途中でDB行のロックを収集するため、非常に大きく、長時間実行されるクエリにはターニングポイントがある可能性があります。非常に大きなクエリは、多くのロックを長期間保持する可能性があり、同時クエリとの摩擦を引き起こす可能性があります。

29