2016-07-27 8 views
0

現在の行から前の行を減算するとクエリが遅すぎるため、これを行うより効率的な方法がありますか? 私は、データフィルタを作成しようとしていますが、そのデータフィルタは、発生しないイベントに順次発生するイベントを強調表示する機能を備えています。私は、時系列順に並べられた機械操作データ「ソース」のテーブルを持っています。 WHERE句を使用するこの特定の分析とはあまり関係のないデータを除外します。残りのデータは新しいテーブル 'filtered'に挿入されます。挿入されたID番号を 'source'から使用して、各行とその進行行を比較して値の差を見つけます。差が1の場合、イベントは順番に発生し、差異がNULLの場合は表示されません。私の問題は、行を前の行と比較するのにかかる時間の長さにあります。データボリュームをフルボリュームの2.5%(275000行)に減らしました.MySQL Workbenchのアクション出力によれば、クエリは3012秒かかります。私は異なる方法でクエリを構造化することを実験しましたが、最終的には行き止まりに達しました。だから私の質問です - 行を前の行と比較する効率的な方法はありますか?現在の行と前の行を比較するとクエリが遅すぎる

OK - ここにいくつかの詳細があります。

/*First I create the table for the filtered data */ 
drop table if exists filtered_dta; 
create table filtered_dta 
( 
ID   int (11)  not null  auto_increment, 
IDx1  int (11), 
primary key (ID) 
); 

/その後、私はここで/

insert into filtered_dta (IDx1) 
     select seq from source 
      WHERE range_value < -1.75 
      and  range_value > -5 ; 

        /* Then I compare each row with its previous */ 

        select    t1.ID, t1.IDx1,(t1.IDx1-t2.IDx1) 
        as     seq_value 
        from    filtered_dta t1 
        left outer join  filtered_dta t2 
        on     t1.IDx1 = t2.IDx1+1 
        order by IDx1 
        ; 

フィルタリングされたデータを挿入するには、サンプルテーブルです。

Table - filtered_dta     Results 

    | ID | IDx1 |    | ID | IDx1 | seq_value | 
    1  3     1  3  null 
    2  4     2  4  1 
    3  7     3  7  null 
    4 12     4 12  null 
    5 13     5 13  1 
    6 14     6 14  1 

ソーステーブルの完全なデータセットは、3〜1,000万行になると予想されます。データベースは約50のテーブルを作成して使用します。このデータベースは、この量のデータを処理し、データが表すシステムの適切な分析を行う能力を持たないシミュレーションソフトウェアのバックエンドエンジンとして使用されています。 私はこの問題について多少の時間を費やして、次のことに気がつきました。 find_seqテーブルがmyISAMで作成され、innoDBテーブルに変換する必要がある可能性があります。デフォルトのエンジンをinnoDBに設定しようとしましたが、目立った違いは見られませんでした。 この質問は、遅いクエリの問題では似ていましたが、問題はwhere句で関数を持つことになりました。私のアクション出力から、where句があまり遅くないことがわかります。 私はこれについて誰でも入力していただければ幸いです。また、私はMySQLの熟練したユーザーではないので、可能であれば詳細を述べる。 よろしくお願いいたします。

+0

filtered_dta'の '' IDx1'のインデックス;しかし、私は結合の '+ 1'操作でどれくらいのことがわかりません。 – Uueerdo

+0

ありがとうございましたUueerdo私は、インデックスを追加し、クエリが6%速く実行されたが見つかりました。それだけでは十分なマージンでクエリ時間が短縮されるわけではありません。 – PhDunce

+0

@Uueerdo - 良い。しかし、 'LEFT'のために' t2.IDx1 = t1.IDx1 + 1'に変更してください。 –

答えて

0

あなたは、自己結合せずに、順次「島」を識別するために、このテンプレートのようなものを使用することができます。

SELECT @island := @island + IF(seqId <> @lastSeqId + 1, 1, 0) AS island 
, orderQ.[fieldsYouWant] 
, @lastSeqId := seqId 
FROM (
    SELECT [fieldsYouWant], [sequentialIdentifier] AS seqId 
    FROM [theTable] AS t 
     , (SELECT @island := 0, @lastSeqId := [somethingItCannotBe]) AS init_dnr -- Initializes variables, do not reference 
    WHERE [filteringConditionsMet] 
    ORDER BY [orderingCriteria] 
) AS orderingQ 
; 

私はできるだけ汎用的としてそれを維持しようとしたが、あなたは私がに戻す必要があった注意しましょうseqIdは数字で、1つ増分すると仮定しています。 islandの条件は、必要に応じてより複雑になる可能性があります((A, 1), (A, 2), (B, 3)は、1つの値で定義されていないシーケンスに基づいて2つの島になる必要があります)。

あなたのような何かのためにサブクエリとして上記のクエリを作る簡単なことで、「島」の境界と大きさを特定するために、さらにこのテンプレートを取ることができます助けるかもしれ

SELECT island, MIN(seqId), MAX(seqId), COUNT(seqId) 
FROM ([above query]) AS islandQ 
GROUP BY island 
; 
+0

華麗なウエエルド - 私の3012秒のクエリーは今や0.218秒かかります。あなたの前提は正しかった - ソース 'seqID'は1だけ増分します。あなたのご意見を大変感謝しています。ありがとうございます。私の投票は私があまりにも戸惑っているので登録しません。 +1。 – PhDunce

関連する問題