2011-08-11 19 views
0

私はH2を使用しています。多対多の関係で接続されたブック(テーブルエントリ)と作成者(テーブルPersons)テーブルの著者。 データベースはかなり大きい(900,000 +人、2.5M +本)。H2で多対多の関係から効率的に選択

名前がパターン(LIKE '%パターン%')に一致する少なくとも1人の作者によってオーサリングされたすべての書籍のリストを効率的に選択しようとしています。ここでのトリックは、パターンが一致する著者の数を大幅に制限し、各著者の関連書籍が合理的に少ないことです。

SELECT p.*, e.title FROM (SELECT * FROM Persons WHERE name LIKE '%pattern%') AS p 
    INNER JOIN Authorship AS au ON au.authorId = p.id 
    INNER JOIN Entries AS e ON e.id = au.entryId; 

と:

私は2つのクエリ試み

SELECT p.*, e.title FROM Persons AS p 
    INNER JOIN Authorship AS au ON au.authorId = p.id 
    INNER JOIN Entries AS e ON e.id = au.entryId 
WHERE p.name like '%pattern%'; 

を私は著者のはるかに小さい(サブ)テーブルを結合していたように最初のものは、はるかに高速であると予想しました、しかし、彼らはどちらも長くかかる。実際には、私は手動で3つの選択肢にクエリを分解し、私がより速くしたい結果を見つけることができます。

私はクエリをEXPLAINしようとすると、実際には非常に似ていることがわかります(テーブルとWHERE句の完全結合)ので、私の質問は次のとおりです。著者のフィルタは、他の2つのテーブルとの結合がずっと小さくなる必要があるという事実に基づいていますか?

私は同じクエリをMySQLで試してみましたが、私が期待していたもの(一番早いものを選ぶほうがはるかに速い)に沿った結果が得られました。

ありがとうございます。あなたのパターンは% MySQLで'%pattern%'開始はどのインデックスを使用することはできませんし、全表スキャンを行う必要がある場合ので

+1

なぜ最初のJOINでSUBSELECTですか?単純に「INNER JOIN authorship AS au ON ...」にならないのはなぜですか? – wonk0

+0

あなたが正しいです、私は変更を加えました。クエリは(少なくともEXPLAINによると)同じものに変換されますが、現在はより簡単です。 – Philippe

+0

これらのクエリの 'EXPLAIN ANALYZE SELECT ... 'の結果は何ですか? –

答えて

1

[OK]をここでは、最終的に私のために働いたものです。

代わりにクエリを実行する:

SELECT p.*, e.title FROM (SELECT * FROM Persons WHERE name LIKE '%pattern%') AS p 
    INNER JOIN Authorship AS au ON au.authorId = p.id 
    INNER JOIN Entries AS e ON e.id = au.entryId; 

...私は走った:

SELECT title FROM Entries e WHERE id IN (
    SELECT entryId FROM Authorship WHERE authorId IN (
    SELECT id FROM Persons WHERE name LIKE '%pattern%' 
) 
)   

を今私はのように、著者のIDを取得していないので、それは正確に同じクエリではありません結果の中の列ですが、私が望んだのはそれです。少数のエントリーだけを検索するためにパターンが著者の数を非常に小さな値に制限するという事実を利用します。

興味深いのは、これがH2でうまくいっていることです(結合よりずっと速い)が、MySQLでは非常に遅いです。 (これはLIKEの '%pattern%'の部分とは関係ありません。他の回答のコメントを参照してください)。私は、クエリが異なって最適化されていると思います。

+1

ニース。 MySQLは外部クエリに対して毎回サブクエリを評価するので、結果を「覚えていない」ため、MySQL btwでは本当に悪いことになります。既知の弱点それを3段階の入れ子にすることは、多くのことを傷つけるでしょう:-) – Brian

+0

ありがとう、それはそれを説明します! – Philippe

0

SELECT * FROM Persons WHERE name LIKE '%pattern%'はいつもあなたが何で900,000+行のテーブルの上に長くはかからないだろう。あなたはfull-text indexes and functionを調べるべきです。

+0

実際、それは遅くない、少なくとも私の目的ではありません(ホッパの答えのコメントを参照)。しかし、リンクをありがとう。 – Philippe

0

まあ、同様の条件はワイルドカードで始まるので、常に遅いフルテーブルスキャンとなり、内部キャッシングは起こりません。

フルテキスト検索を実行したい場合は、mysqlを使用するのが最善の方法ではありません。この種の問題を解決するには、他のソフトウェア(例えばsolr)を調べてください。

+0

2つのこと:1)主にH2を使用しています。私は比較のためだけにMySQLを使用していましたが、おそらくそのタグを削除する必要があります。 2)SELECT * FROM Person WHERE name LIKE '%pattern%';を実行すると、結果がかなり高速になります(H2で半秒、MySQLの1/10)。その結果にはほとんどエントリがありません。本当の疑問は、これらの少数(著者)のエントリに関連する本をどのように素早く得ることができるかです。 – Philippe