2010-11-25 5 views
3

EDIT:以下の質問には、観察結果を説明する間違いがありました。私は質問を削除することができますが、これはまだ誰かにとって有用かもしれません。間違いは、サーバー上で実行されている実際のクエリはSELECT * FROM t(それはばかげていた)だと私は考えていたのだと思っていた。それはSELECT t.* FROM tだ。 tobyobrianの答えとそのコメントを参照してください。この大きなJOINのスピードアップ


次のように、スキーマを使用する状況ではクエリが低すぎます。テーブルtは、t_idによってインデックスされたデータ行を持っています。

CREATE TABLE t (
    t_id INT NOT NULL PRIMARY KEY, 
    data columns... 
); 
CREATE TABLE t_x (
    t_id INT NOT NULL, 
    x_id INT NOT NULL, 
    PRIMARY KEY (t_id, x_id), 
    KEY (x_id) 
); 
CREATE TABLE t_y (
    t_id INT NOT NULL, 
    y_id INT NOT NULL, 
    PRIMARY KEY (t_id, y_id), 
    KEY (y_id) 
); 

私はどちらかで参照されていないもの、すなわちt浮遊行をエクスポートする必要があります:tは、結合に必要なだけforeignsキーが含まれているそれぞれの接合テーブルt_xt_yを経由して、テーブルxyに隣接しますジャンクションテーブル。

SELECT t.* FROM t 
LEFT JOIN t_x ON t_x.t_id=t.t_id 
LEFT JOIN t_y ON t_y.t_id=t.t_id 
WHERE t_x.t_id IS NULL OR t_y.t_id IS NULL 
INTO OUTFILE ...; 

tt_xt_y両方が約25 M行を有するが21 M行を有します。したがって、これは自然にゆっくりとしたクエリになります。

私はMyISAMを使用していますので、t_xt_yのインデックスを事前にロードすることでスピードアップしようと考えていました。 t_x.MYIt_y.MYIの組み合わされたサイズは約1.2Mバイトでしたので、私はそれらの専用キーバッファーを作成し、それらのPRIMARYキーを専用バッファーに割り当て、LOAD INDEX INTOにそれらをキャッシュしました。

しかし、動作中のクエリを見ると、mysqldは約1%のCPUを使用しています。平均システムIOの待ちキュー長は約5であり、mysqldの平均シークサイズは250kの範囲です。さらに、IOのほとんどはt_x.MYIt_x.MYDからmysqldを読み込みます。

私は理解していない:

  1. mysqldがすべてで.MYDファイルを読んでいるのはなぜ?

  2. なぜ、mysqldはプリロードされたt_xt_yインデックスを使用していないのですか?

それは、2つの列の上にあることt_xt_y主キーとは何かを持ってもらえますか?

EDIT:クエリは次のように説明し

| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra  | 
+----+-------------+-------+------+---------------+---------+---------+-----------+----------+-------------+ 
| 1 | SIMPLE  | t  | ALL | NULL   | NULL | NULL | NULL  | 20980052 |    | 
| 1 | SIMPLE  | t_x | ref | PRIMARY  | PRIMARY | 4  | db.t.t_id | 235849 | Using index | 
| 1 | SIMPLE  | t_y | ref | PRIMARY  | PRIMARY | 4  | db.t.t_id | 207947 | Using where | 
+----+-------------+-------+------+---------------+---------+---------+-----------+----------+-------------+ 
+0

これはあなたの質問とは正確には関係ありませんが、いずれの表にも記載されていないものが必要だと言います。これは英語のあいまいなステートメントです。0/2テーブルに記載されていないもの、または1/2または0/2テーブルに記載されていないものが必要ですか?あなたのクエリーが後者を選択します – tobyodavies

+1

また、そのクエリーのためのEXPLAINの出力は何ですか? – tobyodavies

+0

'SELECT t。*'ではなく 'SELECT t.t_id'だけでは違いますか?それが速ければ、後でt. *から...を選択できます。どこのt.t_ID IN(t.t_id ...を選択))? – Konerak

答えて

1

私はあなたの質問の一部1を答えることができる、とあなたはEXPLAINの出力を投稿する場合、私はしてもしなくてもよい部分2にお答えすることができる場合があります

t。*を選択するには、MYDファイルを参照する必要があります。プライマリキーのみがインデックスにあり、要求したデータ列をフェッチするには残りの列が必要です。

つまり、クエリは非常に迅速に結果を素早くフィルタリングしているだけで、必要なすべてのデータをコピーするのに苦労しています。

出力に重複がある可能性があることにも注意してください.1つの行にt_xでは参照はなく、x_yでは3つのt *が3回繰り返されます。 where節が十分に効率的で、実際のデータを読むのに多くの時間が費やされているとすれば、これはおそらく問題の原因になります。それは場合に役立ちます

+0

さて、私の間違いを指摘しました。私が実行していた実際のクエリは、 '*'の前に 't 'を付けませんでした!それは、データファイルからの読書を説明しています。だから私はクエリを停止し、 't_id'だけをエクスポートしようと決めました。現在、mysqldは1つのプロセッサーの100%を消費しており、ファイルシステムIOは 't.MYD'のシーケンシャル読み取りです。 –

+0

あなたは別個の修飾子なしでも重複を取得します。私はそれがあなたが望むものであると疑っています。 – tobyodavies

0

これは、もう少し効率的かもしれあなたの効率select distinctに変更してみてくださいし、次を参照してください。

SELECT * 
FROM t 
WHERE t.id NOT IN (
    SELECT DISTINCT t_id 
    FROM t_x 
    UNION 
    SELECT DISTINCT t_id 
    FROM t_y 
); 
+0

より良いパフォーマンスのために常にinとinを入れ替えてください。存在しません。 –

+0

また、これは間違っています。これはanとnotでなければならないので、orで区切られた2つの別々のサブクエリが必要です。この問合せでは、idがt_xではなくt_yに存在する場合、行は選択されませんが、実際の問合せ問合せでは選択されます。 –

+0

OPは、「どちらのジャンクションテーブルでも参照されていないもの」という、迷惑行をエクスポートする必要があります。なぜ、 '存在する'がMySQLの 'in'よりも効率的だと思うのですか(参考文献を提供できますか?) – symcbean

2

使用していない存在 - 「参加する」または「ではない使用するよりもはるかに良い - これは最速になりますこの奉仕の中で

SELECT t.* FROM t a 
Where not exists (select 1 from t_x b 
        where b.t_id = a.t_id) 
or not exists (select 1 from t_y c 
       where c.t_id = a.t_id); 
+0

もちろん、これはあなたが尋ねた2つの質問とは関係ありません。パフォーマンスをある程度向上させることができます。 –

+0

'Citation needed';) - ' NOT EXISTS'サブクエリが(ref/eq_ref)joinより速く実行するというあなたの主張をバックアップする何かを表示できますか? – Konerak

+0

存在していません。サブクエリに最初のレコードが見つかるとすぐにそれが返されます。サブクエリをtrueまたはfalseに評価するのに十分です。 http://stackoverflow.com/questions/2065329/sql-server-in-vs-exists-performance http://sqlinthewild.co.za/index.php/2010/03/23/left-outer-join-vs -存在しない/ 。私が扱っているほとんどすべてのケースで、存在を使用するとパフォーマンスが大幅に向上します。 in/joinが高速になるような索引が適切に設計されていない場所はほとんどありません(私はこれを読んでいますが、自分自身には何も出ていません)。 –

関連する問題