2011-07-26 10 views
0

私は3つのテーブル - tblpollquestions、tblpollanswers、およびtblpollresponsesを持っています。mysqlの制限結合 - これを行うより効率的な方法はありますか?

ユーザーがまだ応答していないランダムな質問を、それぞれの回答で選択したいと考えています。

以下のSQLは、私が必要とするものを正確に返しますが、3つのSELECTが必要です。確かにより効率的な方法が必要でしょうか?

SELECT 
    poll.id, 
    poll.question, 
    a.answer 
FROM tblpollquestions poll 
INNER JOIN tblpollanswers a ON a.question_id = poll.id 
INNER JOIN (
    SELECT id FROM tblpollquestions WHERE id NOT IN(
     SELECT question_id FROM tblpollresponses WHERE user_id = 1 
    ) ORDER BY RAND() LIMIT 1 
) as t ON t.id = poll.id 
+0

は私によく見えます。どのように実行されますか?説明計画は何を言っているのですか? – Randy

答えて

0

これはtblpollquestionsテーブル内の多くの行がある場合も遅くなることがLEFT JOIN

SELECT 
    poll.id, 
    poll.question, 
    a.answer 
FROM 
    tblpollquestions poll 
INNER JOIN 
    tblpollanswers a 
ON 
    a.question_id = poll.id 
INNER JOIN (
    SELECT 
     q.id 
    FROM 
     tblpollquestions AS q 
    LEFT JOIN 
     tblpollresponses AS r 
    ON 
     q.id = r.question_id 
     AND r.user_id = 1 
    WHERE 
     r.question_id IS NULL 
    ORDER BY RAND() LIMIT 1 
) as t ON t.id = poll.id 

ORDER BY RAND()NOT IN(SELECT...)を切り替えることで少し良く作ることができます。ランダム行の選択に関するその他のアイデアについては、Bill Karwin(スライド142以降)のプレゼンテーションを参照してください。私は少しそれを変更するだろうが

http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back

+0

MySQLは 'ORDER BY RAND()LIMIT 1'を非常にきれいに最適化します - 実際はかなり高速です。以下のクエリと比較している場合は、LE NULL JOINをIS NULLで指定し、NOT EXISTSをMySQLで同じ速度にする必要があります。 (説明を見てください - 彼らは同じでなければなりません)しかし、私はそれをどこで行うことは、参加よりも速くなると思います。編集:おそらくない:http://jan.kneschke.de/projects/mysql/order-by-rand/ - あなたは両方のバージョンを説明し、それに基づいて決定する必要があります。 – Ariel

+0

ORDER BY RAND()の最適化について聞いたことがありません。あなたはそれに関する情報へのリンクを提供できますか?あなたの 'NOT EXISTS'サブクエリのところでは、従属サブクエリを使用しています。私は、MySQL 5.4以降でこれに対処できると思いますが、古いバージョンでは外部クエリの各行に対してこのようなサブクエリを一度実行することで有名です。 – Mchl

+0

ここをクリックしてください:http://dev.mysql.com/doc/refman/5.0/en/limit-optimization.html MySQLは実際にはテーブル全体をrand()でソートするわけではなく、ただ一つの行を取得して停止します。 – Ariel

0

ですが、私には罰金だ:

SELECT 
    poll.id, 
    poll.question, 
    a.answer 
FROM tblpollquestions poll 
INNER JOIN tblpollanswers a ON a.question_id = poll.id 
WHERE poll.id = (
    SELECT id FROM tblpollquestions WHERE NOT EXISTS (
     SELECT * FROM tblpollresponses WHERE user_id = 1 AND question_id = tblpollquestions.id) 
    ORDER BY RAND() LIMIT 1) 

書かれたインデックスを使用し、一つ一つのための参加条件をチェックしていないのより良い仕事をする必要があり、そのようtblpollanswers

は(そのために)(user_id, question_id)ためtblpollresponsesにあなたがUNIQUEインデックス(または主キー)を持っているを確認してください。他のクエリで必要な場合は、逆の順序で列に追加のUNIQUEインデックスを追加することができます。

編集:実際にどこに置いてもそれほど良くないかもしれないhttp://jan.kneschke.de/projects/mysql/order-by-rand/あなたはexplainとクエリと比較する必要があります。

0

使用は次のように参加左:

SELECT ques.id, ques.question, ans.answer FROM tblpollquestions ques 
INNER JOIN tblpollanswers ans ON(ans.question_id = ques.id) 
left join tblpollresponses res on(res.question_id=ques.id and user_id = 1) 
where res.question_id is null ORDER BY RAND() LIMIT 1; 

私はより良い感覚を作るためにあなたの表の別名を変更しました。

関連する問題