3

問題:

ライブラリのチャプターごとに、開発サイクルの各段階でチケットがいくつあるかを示す Trac レポートを作成しています。チケットは 1 つの作業、通常は個々のルーチンを表します。

たとえば、チャプターXのピア レビュー段階にある次のリリース (マイルストーン) のチケットの数。

10 の開発段階と 47 の章があります。

指定された MySQL クエリは 10 の開発段階すべてを対象としていますが、1 つのチャプターのみを対象としており、長さは 25 行です。したがって、すべてのチャプターのクエリ全体は 1200 行を超えています。

Trac によって表示されるエラーはKeyError: 'numrows'、クエリが大きくなる場所です。

クエリを MySQL に直接入力すると、指定されたエラーは次のようになります。Out of resources when opening file (Errcode: 24) (23)

質問:

  • リファクタリング - これは 'より良い' sql の専門家に実行できますか? 巧妙なトリック/高度なテクニックはありますか?

  • アプローチ - 完全に別のアプローチが必要ですか?

  • 構成 - 非常に大きなクエリを受け入れるように MySQL や Trac を構成できますか

ノート:

テーブル内のデータは小さく、明らかなサイズ制限の下にある場合、クエリの実行に時間がかかりません。

クエリは Trac システムから MySQL に渡されます。MySQL は実行できることにいくつかの制限を課します。たとえば、レポートを生成するために trac から送信できるクエリは 1 つだけです。

Trac レポートがどのように見えるかの例は、ここで見ることができます。

クエリ内の%c%*は、スクリプトを介してクエリが生成されたときに実際の章を置き換えるために使用する一意の文字列です。

SELECT '%c%' as Chapter,
(SELECT count(ticket.id) AS Matches FROM engine.ticket INNER JOIN engine.ticket_custom ON ticket.id = ticket_custom.ticket
WHERE ticket_custom.name='chapter' AND ticket_custom.value LIKE '%c%' AND type='New material' AND milestone='1.1.12' AND component NOT LIKE 'internal_engine' AND ticket.status IN ('new','assigned') ) AS 'New',
(SELECT count(ticket.id) AS Matches FROM engine.ticket INNER JOIN engine.ticket_custom ON ticket.id = ticket_custom.ticket
WHERE ticket_custom.name='chapter' AND ticket_custom.value LIKE '%c%' AND type='New material' AND milestone='1.1.12' AND component NOT LIKE 'internal_engine' AND ticket.status='document_interface' ) AS 'Document\
 Interface',
(SELECT count(ticket.id) AS Matches FROM engine.ticket INNER JOIN engine.ticket_custom ON ticket.id = ticket_custom.ticket
WHERE ticket_custom.name='chapter' AND ticket_custom.value LIKE '%c%' AND type='New material' AND milestone='1.1.12' AND component NOT LIKE 'internal_engine' AND ticket.status='interface_development' ) AS 'Inter\
face Development',
(SELECT count(ticket.id) AS Matches FROM engine.ticket INNER JOIN engine.ticket_custom ON ticket.id = ticket_custom.ticket
WHERE ticket_custom.name='chapter' AND ticket_custom.value LIKE '%c%' AND type='New material' AND milestone='1.1.12' AND component NOT LIKE 'internal_engine' AND ticket.status='interface_check' ) AS 'Interface C\
heck',
(SELECT count(ticket.id) AS Matches FROM engine.ticket INNER JOIN engine.ticket_custom ON ticket.id = ticket_custom.ticket
WHERE ticket_custom.name='chapter' AND ticket_custom.value LIKE '%c%' AND type='New material' AND milestone='1.1.12' AND component NOT LIKE 'internal_engine' AND ticket.status='document_routine' ) AS 'Document R\
outine',
(SELECT count(ticket.id) AS Matches FROM engine.ticket INNER JOIN engine.ticket_custom ON ticket.id = ticket_custom.ticket
WHERE ticket_custom.name='chapter' AND ticket_custom.value LIKE '%c%' AND type='New material' AND milestone='1.1.12' AND component NOT LIKE 'internal_engine' AND ticket.status='full_development' ) AS 'Full Devel\
opment',
(SELECT count(ticket.id) AS Matches FROM engine.ticket INNER JOIN engine.ticket_custom ON ticket.id = ticket_custom.ticket
WHERE ticket_custom.name='chapter' AND ticket_custom.value LIKE '%c%' AND type='New material' AND milestone='1.1.12' AND component NOT LIKE 'internal_engine' AND ticket.status='peer_review_1' ) AS 'Peer Review O\
ne',
(SELECT count(ticket.id) AS Matches FROM engine.ticket INNER JOIN engine.ticket_custom ON ticket.id = ticket_custom.ticket
WHERE ticket_custom.name='chapter' AND ticket_custom.value LIKE '%c%'AND type='New material' AND milestone='1.1.12' AND component NOT LIKE 'internal_engine' AND ticket.status='peer_review_2' ) AS 'Peer Review Tw\
o',
(SELECT count(ticket.id) AS Matches FROM engine.ticket INNER JOIN engine.ticket_custom ON ticket.id = ticket_custom.ticket
WHERE ticket_custom.name='chapter' AND ticket_custom.value LIKE '%c%' AND type='New material' AND milestone='1.1.12' AND component NOT LIKE 'internal_engine' AND ticket.status='qa' ) AS 'QA',
(SELECT count(ticket.id) AS Matches FROM engine.ticket INNER JOIN engine.ticket_custom ON ticket.id = ticket_custom.ticket
WHERE ticket_custom.name='chapter' AND ticket_custom.value LIKE '%c%'AND type='New material' AND milestone='1.1.12' AND component NOT LIKE 'internal_engine' AND ticket.status='closed' ) AS 'Closed',
count(id) AS Total,
ticket.id AS _id
FROM engine.ticket
INNER JOIN engine.ticket_custom ON ticket.id = ticket_custom.ticket
WHERE ticket_custom.name='chapter' AND ticket_custom.value LIKE '%c%' AND type='New material' AND milestone='1.1.12' AND component NOT LIKE 'internal_engine'
4

5 に答える 5

3

カウントごとにサブクエリを作成する代わりに、 a を使用しcaseて、クエリ用に既にフェッチされているデータからカウントします。

select '%c%' as Chapter,
  sum(case when ticket.status IN ('new','assigned') then 1 else 0 end) as 'New',
  sum(case when ticket.status='document_interface' then 1 else 0 end) as 'DocumentInterface',
  sum(case when ticket.status='interface_development' then 1 else 0 end) as 'Interface Development',
  sum(case when ticket.status='interface_check' then 1 else 0 end) as 'Interface Check',
  sum(case when ticket.status='document_routine' then 1 else 0 end) as 'Document Routine',
  sum(case when ticket.status='full_development' then 1 else 0 end) as 'Full Development',
  sum(case when ticket.status='peer_review_1' then 1 else 0 end) as 'Peer Review One',
  sum(case when ticket.status='peer_review_2' then 1 else 0 end) as 'Peer Review Two',
  sum(case when ticket.status='qa' then 1 else 0 end) as 'QA',
  sum(case when ticket.status='closed' then 1 else 0 end) as 'Closed',
  count(id) as Total,
  ticket.id as _id
from
  engine.ticket
  inner join engine.ticket_custom on ticket.id = ticket_custom.ticket
where
  ticket_custom.name='chapter' and
  ticket_custom.value LIKE '%c%' and
  type='New material' and
  milestone='1.1.12' and
  component NOT LIKE 'internal_engine'
于 2012-09-26T18:18:21.490 に答える
2

完全に書き直すつもりはありません...しかし、ここに私の提案があります:

SELECT '%c%' as Chapter,
    SUM(CASE WHEN ticket.status IN ('new','assigned') THEN 1 ELSE 0 END) as `New`,
    ...
    SUM(CASE WHEN ticket.status='closed' THEN 1 ELSE 0 END) as 'Closed',
    count(id) AS Total,
    ticket.id AS _id
FROM engine.ticket
INNER JOIN engine.ticket_custom 
    ON ticket.id = ticket_custom.ticket
WHERE ticket_custom.name='chapter' 
    AND ticket_custom.value LIKE '%c%' 
    AND type='New material' 
    AND milestone='1.1.12' 
    AND component NOT LIKE 'internal_engine'
GROUP BY ticket.id
;
于 2012-09-26T18:10:28.783 に答える
1

このような複雑なレポートを Trac で生成する場合は、レポートをまったく使用しない方がよいでしょう。レポートは比較的単純なクエリには問題ありませんが、多数の異なる段階や章を編成すると扱いにくくなります。

代わりに、wiki ページを使用して「レポート」を作成してみてください。これにより、レイアウトとプレゼンテーションをより詳細に制御できるようになり、さらに SQL の記述を完全に回避できます。以下は、未解決のすべてのチケットをマイルストーンとステータス別にグループ化して表示する偽レポートのサンプル Wiki コードです。

= Custom Report =
My custom report, as a wiki page

== Tickets for Milestone A ==
[[TicketQuery(milestone=MilestoneA,status!=closed,group=status,format=table)]]

== Tickets for Milestone B ==
[[TicketQuery(milestone=MilestoneB,status!=closed,group=status,format=table)]]

...

ステージとチャプターがどのように定義されているかわかりません。そのため、適切なチケット フィールドを使用するにはクエリ パラメータを微調整する必要があります。formatやその他のオプションをいじって、出力形式を微調整することもできます。

これは単純な例です。マクロは、TicketQueryより複雑なレポートを生成できます。おそらく探しているものに (複雑さの点で) 近いものの例については、Trac プロジェクトのリリース ノートを参照してください。「変更の詳細リスト」セクション全体が単一のTicketQueryマクロで生成されます (「編集」ボタンをクリックして、どのように実行されたかを確認してください)。


もう一つの例

リンクしたグラフを再作成するには、次のようにします。

||= **Id** =||= **Enhancements** =||= **Defects** =||= **Tasks** =||
||[milestone:v1.0 v1.0] || [[TicketQuery(milestone=v1.0,type=enhancement,format=count)]] || [[TicketQuery(milestone=v1.0,type=defect,format=count)]] || [[TicketQuery(milestone=v1.0,type=task,format=count)]] ||
... repeat for each milestone ...

基本的に、マクロで使用すると、Guffa の回答format=countのステートメントの 1 つに対してデータベースが返すものがわかります。sum(case ...)

直接 SQL の代わりにマクロを使用してこれを行うことの大きな利点は、データベースにとらわれなくなることです。データベース エンジン (mysql、sqlite など) 間の違い、Trac のデータベース レイアウトの変更、カスタム フィールドを処理するための特別なコードなどについて心配する必要はありません。

于 2012-09-26T20:42:52.873 に答える
0

ええ、それは醜いです。そのすべてのデータを 1 行で取得する必要がありますか? その多くのサブクエリはサーバーをバタンと閉めます。標準のグループ化フェッチを実行して、ピボット テーブルをクライアント側で処理することはできませんか?

例えば

SELECT count(ticket.id) AS Matches, ticket_custom.name, ticket.status
FROM engine.ticket
INNER JOIN engine.ticket_custom ON ticket.id = ticket_custom.ticket
WHERE ticket_custom.name='chapter' AND ticket_custom.value LIKE '%c%' AND type='New material' AND milestone='1.1.12' AND component NOT LIKE 'internal_engine' AND ticket.status='qa' AND (ticket.status IN (........))
GROUP BY ticket.id, ticket_custom.name

次に、擬似コードで:

data = array()
while(row = fetch($result)) {
   data[ticket.id]][ticket.status] = row[ticket.status];
}

この方法では、クエリを 1 つだけ実行し、フェッチ ロジックで多少の余分な作業を行って、元のクエリで苦労していることを再作成します。

于 2012-09-26T18:06:24.637 に答える
0

私は自分のトラック報告システムを .NET で書くことになりましたphp。これにより、必要な種類のレポートを作成する柔軟性が大幅に向上し、ばかげたものは含まれませんmysql queries。スクリプトを trac プロジェクトに統合しすぎると、レポート項目、つまり第XXのステージQA でのチケットの数は、trac 内のチケット自体へのハイパーリンクになります: http://myhost.co.uk/trac-project/query?id=10&id =15 . また、NavAddPlugginを使用すると、メインのトラック ナビゲーション バーをカスタマイズできるため、スクリプトにリンクするメニュー オプションを追加できます。

于 2012-10-03T15:13:46.740 に答える