2017-08-01 5 views
0

この表のすべての行を選択しようとしていますが、元のものの代わりに改訂されたIDが選択されています。したがって、ある行にリビジョンがある場合、その行ではなくそのリビジョンが選択されます。複数のリビジョン番号がある場合は、最も高いリビジョン番号が優先されます。改訂された行による自己結合とフィルタリングの実行方法

私は、出力の例表を考えると、クエリは、この優れたを説明します:

表:

+----+-------+-------------+-----------------+-------------+ 
| id | value | original_id | revision_number | is_revision | 
+----+-------+-------------+-----------------+-------------+ 
| 1 | abcd | null  | null   |   0 | 
| 2 | zxcv | null  | null   |   0 | 
| 3 | qwert | null  | null   |   0 | 
| 4 | abd | 1   | 1    |   1 | 
| 5 | abcde | 1   | 2    |   1 | 
| 6 | zxcvb | 2   | 1    |   1 | 
| 7 | poiu | null  | null   |   0 | 
+----+-------+-------------+-----------------+-------------+ 

所望の出力:

+----+-------+-------------+-----------------+ 
| id | value | original_id | revision_number | 
+----+-------+-------------+-----------------+ 
| 3 | qwert | null  | null   | 
| 5 | abcde | 1   | 2    | 
| 6 | zxcvb | 2   | 1    | 
| 7 | poiu | null  | null   | 
+----+-------+-------------+-----------------+ 

revisions_maxというビュー:

SELECT 
    responses.original_id AS original_id, 
    MAX(responses.revision_number) AS revision 
FROM 
    responses 
WHERE 
    original_id IS NOT NULL 
GROUP BY responses.original_id 

私の現在のクエリ:

SELECT 
    responses.* 
FROM 
    responses 
WHERE 
    id NOT IN (
     SELECT 
      original_id 
     FROM 
      revisions_max 
    ) 
AND 
    is_revision = 0 

UNION 

SELECT 
    responses.* 
FROM 
    responses 
INNER JOIN revisions_max ON revisions_max.original_id = responses.original_id 
    AND revisions_max.revision_number = responses.revision_number 

このクエリは動作しますが、実行するために0.06秒かかります。たった2000行のテーブルがあります。この表は、すぐに数十または数十万行に拡大し始めるでしょう。 unionの下のクエリは、ほとんどの時間がかかるものです。

このクエリのパフォーマンスを改善するにはどうすればよいですか?

+0

Hey Douglas、あなたのコードは実行されません。 "列response_idが存在しません"。私はその後のパフォーマンスを比較することはできません。 – clapas

+0

@clapas woops、私は作業しているテーブルから、stackoverflowのより単純なクエリの例に変換しています。私はそれを修正します。 –

+0

テーブルにはどのようなインデックスがありますか?あなたのデータはどのように分布していますか?つまり平均リビジョン数は何ですか? – GarethD

答えて

1

どのように発展して最新に保つていない使用していませんでしたか?

SELECT COALESCE(y.id, x.id)       AS id, 
     COALESCE(y.value, x.value)      AS value, 
     COALESCE(y.original_id, x.original_id)   AS original_id, 
     COALESCE(y.revision_number, x.revision_number) AS revision_number 
FROM responses x 
     LEFT JOIN (SELECT r1.* 
        FROM responses r1 
         INNER JOIN (SELECT responses.original_id   AS 
              original_id, 
              Max(responses.revision_number) AS 
              revision 
            FROM responses 
            WHERE original_id IS NOT NULL 
            GROUP BY responses.original_id) rev 
           ON r1.original_id = rev.original_id 
            AND r1.revision_number = rev.revision) y 
       ON x.id = y.original_id 
WHERE y.id IS NOT NULL 
     OR x.original_id IS NULL; 
+0

Clapas、私は私の質問を編集しました。あなたは、あなたが答える前に変更を見たことがないかもしれません。私は解決策を整理しましたが、パフォーマンスを改善したいと考えています。 –

+0

どのように比較しますか?私はあなたのコードを実行することはできません、ちょうどコメントを投稿してください。 – clapas

+0

Clapasは完全に変換して実行しましたが、それは私よりもはるかに優れています。 大きな質問は、サブクエリをビューにして、関連するパフォーマンスを(私はそれがまったく同じであると想像します) –

1

Iが他のDBMSとかかるアプローチはNOT EXISTSを使用することである。

SELECT r1.* 
FROM Responses AS r1 
WHERE NOT EXISTS 
     ( SELECT 1 
      FROM Responses AS r2 
      WHERE r2.original_id = COALESCE(r1.original_id, r1.id) 
      AND  r2.revision_number > COALESCE(r1.revision_number, 0) 
     ); 

(それが移入されている場合、またはoriginal_id)より高いリビジョン番号が同じIDのために存在するすべての行を削除します。しかし、MySQLでは、LEFT JOIN/IS NULL will perform better than NOT EXISTS です。私はあなたがLEFT JOINを使用し、ヌルをチェックする必要はありませんが、私はそれを見ていないと述べていることを実感

SELECT r1.* 
FROM Responses AS r1 
     LEFT JOIN Responses AS r2 
      ON r2.original_id = COALESCE(r1.original_id, r1.id) 
      AND r2.revision_number > COALESCE(r1.revision_number, 0) 
WHERE r2.id IS NULL; 

Example on DBFiddle

:などとして、私は上記を書き換えますより良い解決策があります。


1.少なくとも、この場合は、歴史的に、私は積極的にMySQLはとてもcoalesce()の使用についてオプティマイザ

+0

ガレス、私はちょうどあなたが答えたときに私の質問を修正し終わった。私は今あなたのことを読んでいます。私はそれを働かせて、パフォーマンスに集中しています。 –

+0

ちょうどテストされた、私が考案した解決策を実行するには、LEFT JOINとCOALESCEのバージョンが〜10倍長くなります。より洗練されたように見えますが –

+0

私はいくつかの不要な合体を取り除きました。フィディングでは(original_idとrevision_numberに)インデックスを追加しましたが、これらの両方が役に立ちますが、インデックスがクエリに役立つ場合はclapasのクエリをさらに高速化する可能性があります。 – GarethD

関連する問題