2013-07-28 2 views
5

にバグのステータス(など)を取得するための最良の(最速)の方法。現在、私は歴史のある日付のデータに基づいてレポートを作成するように変更しています。以前は、今日の状況からのデータしか表示していませんでした。のBugzilla、私はさまざまなソースからデータを取得し、レポートを生成するアプリケーションに取り組んでいる特定の日付

私のデータ源の1つは、Bugzillaのであるので、私は歴史の中で与えられた日付のBugzillaのデータを取得する必要があります。私はBugzillaデータベースへの読み取り専用接続を持っていますが、プラグインのインストールやデータベースへのプロシージャの挿入など、サーバーに何か他の操作を簡単に行う方法はありません。また、レポートサーバーとBugzillaのサーバー間の接続が遅いので、私は、サーバー上で計算を行うのではなく、レポートサーバー上のデータや作業物事をフェッチしたいと思います。

私は実際にこれは主に許容可能な速度で働いていますが、私はそれを最高のか、「正しい」やり方をやっているならば、私たちは追加として速度が許容されるのをやめるかもしれないという心配はよく分かりませんデータベースへのより多くの問題。

だから、私の解決策は以下の通りです - あなたはそれを行うだろうか。

バックグラウンドについては、Bugzillaはすべてのバグの現在の状態(「バグ」と呼ばれます)と、テーブル内の各フィールドの変更履歴(「bugs_activity」)を次のように表示します。

fieldid INTEGER, -- References the fielddefs table 
bug_when TIMESTAMP, -- Time the change happend 
added  TEXT,  -- New text for the field 
removed TEXT,  -- Old text for the field 

BugzillaデータベースはMySQLです。私はそれを行う正しい方法は、ストアドプロシージャまたは一時テーブルのいずれかであると思うが、どちらのオプションも私には利用できません。私はBugzilla用のレポートツールもあると知っていますが、私はそれらをインストールするアクセス権がありません。また、私が生成しているレポートも他のソースからのデータを結びつけています(特定のフォーマットを持っています)。

レポートサーバにはローカルのPostgreSQLデータベースがありますので、すべてのデータを定期的にミラーリングすることができますが、実際には同じデータを2箇所に保存するのは少し無駄に思えます。

私の解決策は、通常のバグ表(特定のレポートに興味があるデータ)のようなサブセレクト内に表を作成し、この選択をソースとして使用して、今日のデータに基づくレポートのクエリと同じです。

SELECT bug_status, bug_id, op_sys, resolution, rep_platform 
    FROM (SELECT bug_id, 
     IFNULL((SELECT removed FROM bugs_activity a, fielddefs f 
       WHERE a.fieldid = f.id 
        AND bug_id = b.bug_id AND f.name = 'bug_status' 
        AND bug_when >= '2012-01-01 00:00:00' 
       ORDER BY bug_when DESC LIMIT 1), bug_status) AS bug_status, 
    -- Repeat IFNULL clause for op_sys, resolution and rep_platform 
     FROM bugs b 
     WHERE b.creation_ts <= '2012-01-01 00:00:00') bug_subselect 
     -- Some other filters to reduce the bugs (specific product, ect) 
    ) 
    -- More filters based on the new values that have been derived 
    ; 

は、次に私が使用していることなどが異なるステータスをカウント選択への入力、など

このクエリは、それがために全体の結果を得ることですので、私はと仮定していますあまりにも遅いことが判明インナーはそれを注文し、私にトップを与えることができるように選択します。

bugs_activityテーブルをバグテーブルに数回ジョインしてから、その結果をIFNULLクエリで処理しましたが、これは高速でしたが、生成コードでは維持するのが少し複雑でしたので、

SELECT bug_status, bug_id, op_sys, resolution, rep_platform 
    FROM (SELECT bug_id, 
    IFNULL((SELECT removed FROM bugs_activity a, fielddefs f 
      WHERE a.fieldid = f.id AND bug_id = b.bug_id AND f.name = 'bug_status' 
       AND bug_when = (
        SELECT MIN(bug_when) FROM bugs_activity a, fielddefs f 
         WHERE a.fieldid = f.id 
          AND bug_id = b.bug_id 
          AND f.name = 'bug_status' 
         AND bug_when >= '2012-01-01 00:00:00' 
          LIMIT 1 
         ) 
      LIMIT 1), bug_status) AS bug_status, 
     -- Repeat IFNULL clause for op_sys, resolution and rep_platform 
     FROM bugs b 
     WHERE b.creation_ts <= '2012-01-01 00:00:00') bug_subselect 
     -- Some other filters to reduce the bugs (specific product, ect) 
    ) 
    -- More filters based on the new values that have been derived 
     ; 

いくつかのフィールドは多分アップグレードから同じタイムスタンプ(のいずれかのデータベースグリッチ、上の2つの変更、または同じバグを編集する二人のユーザーを持っているために管理しているとして、あなたは(私が思う)そこに両方の​​LIMIT 1の者を必要とします - - 私は確信していない、私はそれがそこにあると私はそれに対処する必要があることを知っている)。

これは(最悪のケースであると起こることはほとんどないであろう)バグリストを減らすためにフィルタなしで約3秒で実行され、それはより速くフィルタを使用して実行されます。 LEFT JOINバージョンはほぼ同じスピード(わずかに遅い)で動作するので、上記のものと一緒に行きました。今のところ問題ありませんが、将来的には遅くなることがわかります。GUIに読み込みメッセージを追加します。これらのレポートの生成に時間がかかりそうだというメッセージが既に表示されています。それをより速くするためにいくつかのトリックがありません。

+0

"私はそれをより速くするためにいくつかのトリックを欠けている場合、私はただ思ったんだけど" - うん。それらはインデックスと呼ばれています... –

+1

bugs_activityテーブルにはインデックスがありません。 – SpaceDog

+0

私は私が言ったことを正確に意味しました - インデックスはクエリをスピードアップします。 –

答えて

1

私はあなたが正しくあなたがこれを試みることができる取得していた場合...

SET @tdate = '2012-01-01 00:00:00'; 

SELECT 
    b.bug_id 
    ,CASE 
    WHEN s.removed IS NULL THEN b.bug_status 
    ELSE s.removed 
    END AS statusAtDate 
    ,CASE 
    WHEN o.removed IS NULL THEN b.op_sys 
    ELSE o.removed 
    END AS apSysAtDate 
FROM 
    bugs AS b 
    LEFT OUTER JOIN (
    SELECT 
     a.bug_id 
     ,a.bug_when 
     ,a.removed 
     ,a.bug_when 
     ,@row_num := IF(@last=a.bug_id,@row_num+1,1) AS rnk 
     ,@last:=a.bug_id 
    FROM 
     bug_activity AS a 
     INNER JOIN fielddefs AS f 
     ON a.fieldid = f.id 
      AND f.name = 'bug_status' 
    WHERE 
     a.bug_when <= @tdate 
    ORDER BY 
     a.bug_id 
     ,a.bug_when 
    ) AS s 
     ON b.bug_id = s.bug_id 
     AND s.rnk=1 
    LEFT OUTER JOIN (
    SELECT 
     a.bug_id 
     ,a.bug_when 
     ,a.removed 
     ,a.bug_when 
     ,@row_num := IF(@last=a.bug_id,@row_num+1,1) AS rnk 
     ,@last:=a.bug_id 
    FROM 
     bug_activity AS a 
     INNER JOIN fielddefs AS f 
     ON a.fieldid = f.id 
      AND f.name = 'op_sys' 
    WHERE 
     a.bug_when <= @tdate 
    ORDER BY 
     a.bug_id 
     ,a.bug_when 
    ) AS o 
     ON b.bug_id = o.bug_id 
     AND o.rnk=1 

--repeat for resolution and rep_platform 

タイプミスまたは類似がある場合、私はとても残念コードを検証するために、ここでDBを持っていない申し訳ありません...

前に左外部結合をやっていたのかどうか分かりませんが、再利用のためにセッション変数を使用すると助けてくれますか?

これは、あなたの左外部結合メソッドが同じ速度で実行されていると言われているので、何の助けになるかわかりません。おそらくmysqlクエリオプティマイザは、

私は最適化のエキスパートではありません(遠くから)。ちょうど私が外出先でいくつかのインデックスを得るための良い提案以外のものを試してみたいと言っています。

EDIT:

あなたが..私は、これは動作するはず思い試みることができるもう一つ..

SELECT 
    bug_id 
    ,bug_status 
    ,op_sys 
    ,max(old_status) 
    ,max(old_opSys) 
(
SELECT 
    * 
FROM 
    bugs AS b 
    LEFT OUTER JOIN (
    SELECT 
     a.bug_id 
     ,a.bug_when 
     ,if(f.name = 'bug_status',a.removed,NULL) AS old_status 
     ,if(f.name = 'op_sys',a.removed,NULL) AS old_opSys 
     ,a.bug_when 
     ,@row_num := IF(@last=a.bug_id [email protected]=f.name ,@row_num+1,1) AS rnk 
     ,@last:=a.bug_id 
     ,@lastField:=f.name 
    FROM 
     bug_activity AS a 
     INNER JOIN fielddefs AS f 
     ON a.fieldid = f.id 

    WHERE 
     a.bug_when <= '2012-01-01 00:00:00' 
     AND f.name in('bug_status','op_sys') 
    ORDER BY 
     a.bug_id 
     ,f.name 
     ,a.bug_when 
    ) AS s 
     ON b.bug_id = s.bug_id 
     AND s.rnk=1 
) AS T 
    GROUP BY 
    bug_id 
    ,bug_status 
    ,op_sys 

私はここで選択した場合を残したり、外からのif文しています。私はどのソリューションをどのようにテストする価値があるかもしれないと思っていたのは、DBではなくコードで最終チェックを実行していますか?たとえそれが働いてもそれを選ぶことはできないかもしれませんが、それはチェックの価値があるかもしれません。以下のようなもののように

<%= row->old_status ?: row->bug_status %> 

(私のPHPがオフの場合は申し訳ありません...本当に多くのそれを使用していない)、それは動作するはずのよう

はそう? http://sqlfiddle.com/#!2/eff8c/1

+0

あなたは、すべてのフィールドについて一度だけアクティビティテーブルに参加し、bug_idまたはフィールド名が変更されるたびにrnkカラムを変更することで、ファンキーなことをすることができます。 bug_idとmaxを1つおきにグループ全体をラップします。mysqlのようなテキストフィールドを最大限に活用できるかどうかを知ることはできません。 – gordatron

+1

お返事いただきありがとうございます。興味深いアプローチですが、私はそれをちょっと試してみる必要があります。しかし、現在私のアプローチよりも約6倍遅いです。興味深いことに、@tdateがNULLの場合(私はそれを設定するのを忘れてしまったので)、はるかに高速です。私はサーバが賢明な最適化を行っていると推測します。私はいくつかのテストとプロファイリングを行いますが、それは少なくとも私が探求するいくつかの道を与えてくれます。 :) – SpaceDog

+0

このような大きな速度差!あなたが持っているif文のcase文を入れ替えてみるかもしれません。私はデフォルトのオプション(柔軟性と可読性が向上しているため)しかしませんでしたが、この場合よりもかなり遅いかもしれません。また、row_numberの部分はかなり遅いかもしれません。たぶん1回だけ行う価値があります。 – gordatron

1

Bugzilla DBに直接アクセスするのではなく、Bugzilla REST APIインターフェイスを使用することをお勧めします。 特定の日付に作成されたバグを取得するAPIの例を次に示します。

https://api-dev.bugzilla.mozilla.org/test/1.3/bug?creation_date=2008-03-31

参考文献:
https://wiki.mozilla.org/Bugzilla:REST_API
https://wiki.mozilla.org/Bugzilla:REST_API:Objects
https://wiki.mozilla.org/Bugzilla:REST_API:Search

+0

私はREST APIを見ましたが、それはかなりバグだったと読んでいます(これは私たちの古いバージョンにあるかもしれませんが、すぐに更新しています)。また、2012年1月1日に「バグ1234の状態はどうだった?」と質問するのはかなり難しいようです。チェンジセットをダウンロードして解析する必要があるように見えます。おそらくそれを行う複雑なブールクエリがあると思います。私はチャンスがあるときにテストを行いますが、SQLクエリよりも速くなるように遅いリンクを介して情報を転送するように見えます(サブテーブルでCOUNTを行い、生の合計を返すだけなので) 。 – SpaceDog

+0

どこでREST APIがかなりバグだったのを読んだのですか?メンテナーとして、現在のバージョンは非常に安定しており、Mozillaプロジェクトでは週に数十万件のクエリに使用されています。 間もなく、互換性のあるシムで同じインターフェイスを持つネイティブREST APIに置き換えられますが、はるかに高速で、返されるデータには制限が少なくなります。 –

関連する問題