我正在开发一个从各种来源获取数据并生成报告的应用程序。目前,我正在将其更改为根据历史上给定日期的数据进行报告,以前它只显示来自今天事物状态的数据。
我的数据源之一是 Bugzilla,因此我需要获取历史上给定日期的 Bugzilla 数据。我有一个到 Bugzilla 数据库的只读连接,但没有简单的方法对服务器执行任何其他操作(例如安装插件或将程序放入数据库)。报告服务器和 Bugzilla 服务器之间的连接也很慢,所以我想在服务器上进行计算,而不是在报告服务器上获取数据并解决问题。
实际上,我的工作速度几乎可以接受,但我不确定我是在做最好的还是“正确”的方式,我担心随着我们向数据库。
所以,我的解决方案如下 - 你会怎么做。
对于一些背景知识,Bugzilla 将所有 bug 的当前状态存储在一个表中(称为“bugs”)以及表中每个字段的更改历史记录(“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 数据库,所以我可以定期将所有数据镜像到那里,但我真的不想这样做,因为在两个地方存储相同的数据似乎有点浪费。
我的解决方案是在子选择中构建一个看起来像普通错误表的表(对于给定报告我感兴趣的数据),然后将此选择用作与查询相同的正常选择的源报告基于今天的数据。
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 表多次左连接到 bugs 表上,然后对结果进行 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
;
您需要两个 LIMIT 1 (我认为),因为某些字段设法在同一时间戳上进行了两次更改(数据库故障,可能来自升级,或者两个用户编辑相同的错误 - 我不确定,我只知道它在那里,我需要处理它)。
这在没有过滤器的情况下运行大约 3 秒以减少错误列表(这是最坏的情况,几乎永远不会发生),并且使用过滤器运行得更快。LEFT JOIN 版本的运行速度大致相同(稍慢),所以我选择了上面的那个。目前还可以,但我可以看到它将来会变慢——我将在 GUI 中添加一条加载消息,并且已经有一条消息说这些报告可能需要更长的时间才能生成,我只是想知道我是否'我错过了一些让它更快的技巧。