问题:
我正在创建一个Trac报告,显示我们图书馆每章开发周期中每个阶段的门票数量。 门票代表一件作品,通常是个人例程。
例如,即将发布的版本(里程碑)的票数是在 X 章节的同行评审阶段。
共有10个发展阶段和47个章节。
给定的MySQL查询适用于所有10个开发阶段,但只有一个章节并且长度为25行,因此所有章节的整个查询超过1200行。
Trac给出的错误是KeyError: 'numrows'
,查询变得很大。
将查询直接输入MySQL时,给出的错误为Out of resources when opening file (Errcode: 24) (23)
问题:
重构 - 这可以做得更好'sql gurus,有一些聪明的技巧/推进技巧吗?
方法 - 我是否需要完全不同的方法?
配置 - 可以将MySQL和/或Trac配置为接受非常大的查询
注意:
表中的数据很小,查询在表观大小限制下执行时间不长。
查询从Trac系统传递到MySQL,这对可以执行的操作设置了一些限制,例如,只能从trac发送一个查询来生成报告。
可以看到Trac报告的示例here.
查询中的%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'
答案 0 :(得分: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
;
答案 1 :(得分:2)
不是为每个计数创建一个子查询,而是使用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'
答案 2 :(得分:1)
当通过Trac生成这样的复杂报告时,最好不要使用报告。对于相对简单的查询,报告是可以的,但是当您组织许多不同的阶段和章节时,它们会变得难以处理。
相反,请尝试使用Wiki页面创建“报告”。这将使您可以更好地控制布局和演示,还可以避免完全编写SQL。这是一个虚假报告的示例维基代码,显示按里程碑分组的所有非关闭故障单,然后按状态分类:
= 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 project's release notes。使用单个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 ...
基本上,在宏中使用format=count
可以为Guffa的答案中的sum(case ...)
语句之一返回数据库返回的内容。
使用宏而不是直接SQL执行此操作的最大好处是它与数据库无关。您不必担心数据库引擎(mysql,sqlite等)之间的差异,Trac数据库布局的变化,处理自定义字段的特殊代码等等。
答案 3 :(得分:0)
Yeek,那很难看。您是否必须在一行中获取所有数据?许多子查询将抨击服务器。你能不进行标准的分组获取并在客户端进行数据透视表填充吗?
e.g。
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];
}
通过这种方式,您只需运行一个查询,并在获取逻辑中执行一些额外的小工作,以重新创建原始查询正在进行的操作。
答案 4 :(得分:0)
我最终在php
编写了我自己的trac报告系统。这样可以更灵活地创建我需要的报告,并且不会涉及荒谬mysql queries
。要将脚本与trac项目集成,报告项即 QA 中 QA 阶段的门票数量是超链接到门票本身在trac:http://myhost.co.uk/trac-project/query?id=10&id=15 。此外,NavAddPluggin允许自定义主trac导航栏,以便添加链接到脚本的菜单选项。