2009-03-19 17 views
4

MySQL 5.0.67でHibernateのJPA実装を使用しています。 MySQLはInnoDBを使用するように設定されています。SQL IN節が個々のクエリよりも遅い

JPAクエリ(SQLに変換される)を実行すると、IN句を使用すると個々のクエリを実行するよりも処理速度が遅くなることがわかりました。例:

SELECT p FROM Person p WHERE p.name IN ('Joe', 'Jane', 'Bob', 'Alice') 

は、4つの別々のクエリより遅いです:

SELECT p FROM Person p WHERE p.name = 'Joe' 
SELECT p FROM Person p WHERE p.name = 'Jane' 
SELECT p FROM Person p WHERE p.name = 'Bob' 
SELECT p FROM Person p WHERE p.name = 'Alice' 

これはなぜでしょうか?これはMySQLのパフォーマンス制限ですか?あなたはIN演算子を使用している場合、それは非常に異なると言っ以上ではありません

答えて

11

これはMySQLの既知の欠点です。

多くの場合、UNIONを使用すると、表示されたような範囲のクエリよりも優れています。 MySQLは、IN (...)を使用する式には非常に賢明にインデックスを使用しません。類似の穴がブール式のオプティマイザに存在し、ORです。

いくつかの説明と詳細なベンチマークについては、http://www.mysqlperformanceblog.com/2006/08/10/using-union-to-implement-loose-index-scan-to-mysql/を参照してください。

オプティマイザは常に改良されています。次のバージョンでは、あるバージョンのMySQLの欠点が改善される可能性があります。したがって、異なるバージョンのクエリをテストする価値があります。

UNIONの代わりにUNION ALLを使用することも有利です。どちらのクエリでも結果を格納するために一時テーブルが使用されますが、違いはUNIONが結果セットにDISTINCTを適用することで、索引なしの追加ソートが発生します。

+0

SQL Serverにはこの欠点がありますか? –

+0

私はSQL Serverユーザーではないので、その答えはわかりません。実行するのが最善の方法は、クエリアナライザで両方のクエリフォームを試し、実行計画を表示メニューオプションを使用します。 –

+0

いいえ、SQL Serverにはこの問題はありません –

1

(p.name = 'Joe' OR p.name = 'Jane' OR p.name = 'Bob' OR p.name = 'Alice') 

者は、クエリが考慮しなければならないことをすべての行をチェックしなければならない4つの条件です。もちろん、あなたが引用するお互いの質問には1つの条件しかありません。クライアントが結果セットを読み込んで何かを行うのにかかる時間を考慮する必要があるため、4つのクエリを実行するほとんどの現実のシナリオがより高速になるとは思いません。その場合、INはかなりいいようです。インデックスを使用できる場合はさらに優れています。

0

ウォールクロックの時間やクエリの実行時間を測定していますか?私の推測では、4つの個々のクエリのそれぞれの実際の実行時間は、INクエリを実行する時間よりも短くなる可能性がありますが、4つのクエリでは全体の壁時計の時間がかなり長くなります。

名前欄にインデックスを付けると便利です。

+0

合計経過時間を測定しています。 –

1

INのように単純なクエリでは、インデックスを使用するオプティマイザに問題があってはいけません。 Billによって言及されたUNIONの作業は、より複雑なクエリがある場合にのみ必要となることがあります。これは、索引統計に関する問題である可能性があります。

問題のテーブルでANALYZEを実行しましたか?

テーブルには何行あり、IN句にはいくつの行が一致していますか?

問題のクエリについてEXPLAINから何が通知されますか?

0

IN句は、データベースとテーブルを他の接続で使用できるように解放し、アプリケーション構造のメリットがあるため、IN句はわずかな遅延があっても非常に貴重なツールです個々のクエリ。

以下の手法は、私が構築するほとんどのPHP/MySQLアプリケーションで利用されています。

私は、IN節を数字キーでかなり使用します:

グラブ5マスター項目とすべてのsubitesは次のようになります。その後、

$master_arr = mysql_query(
select * from master table where master_id in (1,7,9,10) 
); 

$subitem_arr = mysql_query(
    select * from subitems table where par_master_id in (1,7,9,10) 
); 

マスターアイテムに部分配列を追加します。

foreach($subitem_arr AS $sv){ 
    $m_key = $sv['par_master_id']; 
    $s_key = $sv['subitem_id']; 
    $master_arr[$m_key]['subitem'][$s_key] = $sv; 
} 

これは2つのことを行います: 1.)テーブルはすべて一度に結合で保持されているわけではありません 2)の2つだけのMySQLのクエリはあなたが最初の値を取得するSQL文にSQLクエリを埋め込むのではなく、句でに値を埋め込む場合は、句の高速化することができ、データ

関連する問題