2016-11-10 11 views
1

同じテーブル内の日付フィールドに基づいて一意の最新結果を取得するには、以下のクエリを実行しています。しかし、このクエリは、テーブルが大きくなると時間がかかりすぎます。これを改善するための提案は大歓迎です。クエリの実行に時間がかかります

select 
    t2.* 
from 
    (
     select 
      (
       select 
        id 
       from 
        ctc_pre_assets ti 
       where 
        ti.ctcassettag = t1.ctcassettag 
       order by 
        ti.createddate desc limit 1 
      ) lid 
     from 
      (
       select 
        distinct ctcassettag 
       from 
        ctc_pre_assets 
      ) t1 
    ) ro, 
    ctc_pre_assets t2 
where 
    t2.id = ro.lid 
order by 
    id 

私たちの能力は同じ行を複数回含むことができますが、各行は異なるタイムスタンプを持ちます。私のオブジェクトは単一の列に基づいています。たとえば、assettag最新のタイムスタンプを持つ各アセットタグに対して1行を取得したいとします。

+4

テーブル定義とEXPLAIN出力を指定してください。 –

+1

インデックスを使用しようとしましたか? – Dezigo

+0

インデックスを追加した後は大丈夫ですが、それでもまだ遅いです。 20秒以上かかる – Rajesh

答えて

0

ctcassettagの最新の日付を見つけて、それに戻って一致する行全体を見つける方が簡単で、おそらく高速です。

これは何のctcassettagはあなたctcassettagごとに複数の行を取り戻すことができ、その場合には同じcreateddateを持つ複数の行を、持っていないことを前提としていません。

SELECT 
    ctc_pre_assets.* 
FROM 
    ctc_pre_assets 
INNER JOIN 
(
    SELECT 
     ctcassettag, 
     MAX(createddate) AS createddate 
    FROM 
     ctc_pre_assets 
    GROUP BY 
     ctcassettag 
) 
    newest 
     ON newest.ctcassettag = ctc_pre_assets.ctcassettag 
     AND newest.createddate = ctc_pre_assets.createddate 
ORDER BY 
    ctc_pre_assets.id 

EDIT:同じ日に複数の行に対処します。

に同じctcassettagの複数の行がある場合に、実際にどの行を選択するかは述べていません。したがって、この解決策は、duplicatesの中で最も低いidの行を選択するだけです。

SELECT 
    ctc_pre_assets.* 
FROM 
    ctc_pre_assets 
WHERE 
    ctc_pre_assets.id 
    = 
    (
     SELECT 
      lookup.id 
     FROM 
      ctc_pre_assets lookup 
     WHERE 
      lookup.ctcassettag = ctc_pre_assets.ctcassettag 
     ORDER BY 
      lookup.createddate DESC, 
      lookup.id   ASC 
     LIMIT 
      1 
    ) 

これはまだ(例えば私の最初の答えとして)、単純なネストされたサブクエリより遅いサブクエリを、相関使用していますが、それは「重複」と契約を行います。

関連するサブクエリのORDER BYを変更することで、どの行を選択するかのルールを変更できます。

また、自分のクエリと非常によく似ていますが、結合が1つ少なくなります。

+0

ありがとうございます。時間が正確に一致する場合、クエリは重複した値を返します。しかし、私は1つだけのエントリが欲しい。 – Rajesh

+0

あなたはそれを助けてもらえますか? – Rajesh

+0

@Rajesh - データについて質問する私のコメントに答えてください;)また、私はそれらが重複しないと信じています、彼らは異なる 'id'を持っているでしょう。だから、問題は、どのように*あなたが返す行を選択したいのですか? 2つの行が同じ 'ctcassettag'に対応し、' createddate'と同じものを持っている場合、*あなたは何をしたいですか? – MatBailie

0

ネストされたクエリは、通常のクエリより長い時間がかかることが常に知られています。クエリの最初に「説明」を追加して結果をここに入力できますか?これは、応答に時間がかかる正確なクエリ/テーブルを分析するのに役立ちます。

テーブルにインデックスがあるかどうかを確認します。インデントされていないテーブルは(明らかにインデントを解除する必要がない限り)推奨されず、クエリの実行が非常に遅くなります。

それどころか、ネストされたクエリを完全に書くことを避けるのが最善のケースだと思います。 Betteでは、それぞれのクエリを個別に実行し、2番目のクエリで結果を配列またはリスト形式で使用します。まず

+1

これは、おそらく答えではなくコメントでなければなりません。 –

+0

テーブルにはすでにインデックスがあります。あなたが提案したように私は別々のクエリを実行してみましょう。 – Rajesh

+1

ネストされた問合せでは、実行時間が長くかかったり、コストのかかる説明計画が必要になることはありません。この信念は、説明計画がどのように生成されるのか理解していないことから生じる傾向があります。知識が不足しているということは、パフォーマンスの低いクエリを作成して理由を知らないのは簡単だということです。例えば ​​'SELECT * FROM(SELECT * FROM tbl WHERE x = 1)AS x1 WHERE y = 2'は' SELECT * FROM tbl WHERE x = 1 AND y = 2'を使うのと同じことをします。常にネストされたクエリは、インデックスが難読化されたり、単純に入れ子になっているだけでなく、ひどく書き込まれた計算を含んでいるため、パフォーマンスが低下します。 – MatBailie

0

あなたは、少なくとも自問してみて、多分も私たちの応答の精度を向上させるために答えを与える必要がありますいくつかの質問:

  1. は、あなたのデータは正規化されていますか?はいの場合は、この残虐なサブクエリの問題を避けるために例外を作成する必要があります。
  2. インデックスを使用していますか?はいの場合は、どのものを使用していますか?読みやすさと、クエリのかもしれないパフォーマンスを向上させるために

ヒント: - で使用グループ - - 使用し に合流使用アグリゲータ

例(未テストなので、動作しない可能性がありますが、印象を与える必要があります):

SELECT t2.* 
FROM (
    SELECT id 
    FROM ctc_pre_assets 
    GROUP BY ctcassettag 
    HAVING createddate = max(createddate) 
    ORDER BY ctcassettag DESC 
) ro 
INNER JOIN ctc_pre_assets t2 ON t2.id = ro.lid 
ORDER BY id 

正規化を使用すると効果は大きくなりますが、正規化が問題よりも害を及ぼす場合があります。これはこのような状況のようですが、あなたのテーブルが私の前になくても、私は確信が持てません。

あなたの行っている方法とは異なる方法を使用して、関連するすべての結果が得られない可能性があります。他の誰かがこれを確認したり拒否したりする可能性があります。

サブクエリがすべて悪いわけではありませんが、誤って記述された場合は大規模なスケーラビリティの問題が発生する傾向があります。

インデックスを使用すると、実際に使用する場合には、時間を節約できる可能性があります。それらを設定するだけでは不十分です。インデックスを実際に使用するクエリを作成する必要があります。 Googleも同様です。

+1

内部クエリ( 'ro')は' LIMIT 1'を使用していますので、1行しか返せません。しかし、Opのクエリは、***それぞれの***固有の 'ctcassettag'に対して1行を返します。 – MatBailie

+0

@MatBailieあなたは絶対に正しいです、私の心を滑りました。しかし、LIMIT 1を完全に削除すると正しい結果が得られますか? –

+0

私はそれを試してみる必要がありますが、おそらくMySQLの特定の動作のためです。あなたは 'ORDER BY MAX(createddate)'などが必要かもしれませんが、私はそれを試してもわかりません。しかし、最も適切なのは、この振る舞いが確定的であることが保証されているかどうかであり、そうではありません。この「トリック」はほとんどいつでも動作しますが、ドキュメンテーションでは、実際に*常に*働いている*ことはできません。実際、それは明示的に「不確定」であると言います。 – MatBailie

関連する問題