2017-05-08 28 views
1

私はこの質問が100回尋ねられていることを知っています。これは "どうやってやるの?"ではなく、効率的な質問です。約。"最も最近の行"に参加する最も効率的な方法

私のインターネットの読書から、私はそれがかなり効率的であると聞こえる最新の問題を解決する一つの方法を決めました - マッチする条件でグループ化された "最大"テーブルをLEFT JOINし、LEFT JOINグループ化された条件。このようなもの:

Select employee.*, evaluation.* form employee 
LEFT JOIN (select max(report_date) report_date, employee_id 
     from evaluation group by employee_id) most_recent_eval 
    on most_recent_eval.employee_id = employee.id 
LEFT JOIN evaluation 
    on evaluation.employee_id = employee.id and evaluation.report_date = most_recent_eval.report_date 

私には分からない問題がありますか?これは2回のテーブルスキャン(1つは最大値、1つは行を見つける)ですか?それはすべての従業員のために2フルスキャンを行う必要がありますか?

最新の行(評価、セキュリティのクリアランス、プロジェクト)が必要な3つのテーブルに参加しようとしているので、非効率的なものが大規模に増えるようです。

誰も私にこれに関するいくつかのアドバイスを与えることができますか?

+0

'explain select ...'を実行すると、クエリ。 MySQLのウェブサイトには、結果を解釈する方法の詳細なガイダンスがあります。 Explain出力がなければ、照会の効率はわかりません。 – Shadow

+0

これは単純な例であり、無関係の列がたくさん含まれている実際のクエリの出力で問題をクラウド化しないようにしています。私は本当に "最近の"結合を解決する様々な方法の効率に関するより一般的なガイダンスを探しています。私は今説明の出力の本を開封しますので、そのポインタに感謝します。 – whiteatom

+0

Explainの結果を見ると、最も最近のevalが派生テーブルのデカルト結合(結合タイプのALLを表示)を実行するためのサブクエリが表示されます。私はstart_dateのインデックスを持っています - それは使わないべきでしょうか? – whiteatom

答えて

0

あなたが提案するクエリパターンでは、かなり良い形になるはずです。

可能な提案は、evaluationテーブルに独自の自動インクリメントがあるidカラムがある場合に役立ちます。あなたは次のようになります。参加後

  SELECT MAX(id) id 
       FROM evaluation 
      GROUP BY employee_id 

:あなたこのサブクエリで各従業員のための最新の評価を見つけることができるかもしれ

 FROM employee 
    LEFT JOIN (
       SELECT MAX(id) id 
       FROM evaluation 
       GROUP BY employee_id 
      ) most_recent_eval ON most_recent_eval.employee_id=employee.id 
    LEFT JOIN evaluation ON most_recent_eval.id = evaluation.id 

これが動作するのであれば、あなたのid値とあなたのreport_dateevaluationテーブルの値の順序は同じです。あなたのアプリケーションの場合は、あなただけが知っている。しかし、そうであれば、これは非常に有益な最適化です。

それ以外の場合は、クエリを高速化するために、いくつかの複合インデックスをいくつかのテーブルに追加する必要があります。最初に正しく動作するようにしてください。 http://use-the-index-luke.com/を読んでください。多くの単一列インデックスは、特定のクエリを高速化するように選択されていない限り、一般的にMySQLクエリのパフォーマンスに有害であることに注意してください。

あなたは(employee_id, report_date)に複合インデックスを作成する場合は、このサブクエリ

select max(report_date) report_date, employee_id 
    from evaluation 
    group by employee_id 

は驚くほど効率的loose index scanに満足することができます。あなたはInnoDBテーブルを使用している場合も同様に、クエリ

  SELECT MAX(id) id 
       FROM evaluation 
      GROUP BY employee_id 

employee_id上の単一列索引の緩いインデックス・スキャンによって満たすことができます。 (MyISAMを使用している場合は、複合インデックスが(employee_id, id)である必要があります。これは、InnoDBが主キー列を暗黙的にすべてのインデックスに入れるためです)。

+1

この作業が完了したら、まだヘルプが必要な場合は、クエリのパフォーマンスについて別の質問をすることを検討してください。これを最初に読んでください。特にクエリのパフォーマンスに関する部分を読んでください。 http://meta.stackoverflow.com/a/271056/ –

+0

評価が順番に入力されているかどうかわからないので、IDを使用することはできませんが、タイムスタンプを使用しています(int(11)列)を使用して数値ソートを行います。私はuse-the-index-luke.comで今読んでいます。ありがとう。私は、あなたが提供したリンクに示唆されているように、今後のパフォーマンスに関する質問にもっと詳しく説明します。私は、私が使用している新しい日付ベースのテーブル構造を使用して書き込むための新しいクエリがたくさんあるので、より一般的な "正しい方向"の答えを探していたと思います。 – whiteatom

+0

'DATETIME'と' TIMESTAMP'のデータ項目は、整数と同じようにインデックス付けするのと同じくらい良いことを知っておく必要があります。インデックス/オーダーのパフォーマンスを上げるために、時間/日付値に不自然な行為をする必要はありません。 –

関連する問題