4

嘿。考虑下面的表格和数据......

in_timestamp | out_timestamp | name  | in_id | out_id | in_server | out_server | status
timestamp1   | timestamp2    | data1 |id1   | id2    | others-server1   | my-server1 | success
timestamp2   | timestamp3    | data1 | id2   | id3    | my-server1   | my-server2 | success
timestamp3   | timestamp4    | data1 | id3   | id4    | my-server2   | my-server3 | success
timestamp4   | timestamp5    | data1 | id4   | id5    | my-server3   | others-server2 | success
  • 以上数据代表了一些数据跨服务器的执行流程的日志。
  • 例如,一些数据已经从一些'outside-server1' 流向了一堆'my-servers',最后流向了'others-server2'。

问题 :

1)我需要将此日志以可表示的形式提供给客户端,他不需要知道任何关于“我的服务器”的信息。我应该提供的只是输入我的基础设施的数据的时间戳以及它离开的时间;深入了解以下信息。

in_timestamp (of 'others_server1' to 'my-server1')
out_timestamp (of 'my-server3' to 'others-server2')
name 
status

我想写同样的sql!有人可以帮忙吗?注意:可能不会一直有 3 个“我的服务器”。它因情况而异。例如,可能涉及 4 个“我的服务器”,例如 data2!

2) SQL 是否有其他替代方案?我的意思是存储过程/等?

3) 优化?(记录数量巨大!截至目前,每天大约有 500 万条记录。我们应该显示长达一周的记录。)

在此先感谢您的帮助!:)

4

4 回答 4

2
WITH RECURSIVE foo AS
        (
        SELECT  *, in_timestamp AS timestamp1, 1 AS hop, ARRAY[in_id] AS hops
        FROM    log_parsing.log_of_sent_mails
        WHERE   in_server = 'other-server1'
        UNION ALL
        SELECT  t_alias2.*, foo.timestamp1, foo.hop + 1, hops || in_id
        FROM    foo
        JOIN    log_parsing.log_of_sent_mails t_alias2
        ON      t_alias2.in_id = (foo.t_alias1).out_id 
        )
SELECT  *
FROM    foo
ORDER BY
        hop DESC
LIMIT 1
于 2010-04-08T11:58:51.633 回答
1

您的表具有层次结构(邻接列表)。这可以在 PostgreSQL v8.4 及更高版本中使用递归 CTE 有效地查询。Quassnoi写了一篇关于如何实现它的博客文章。这是一个您需要编写的非常复杂的查询,但他用与您需要的非常相似的示例很好地解释了它。特别是如果您查看他的最后一个示例,他演示了一个查询,而不是使用数组获取从第一个节点到最后一个节点的完整路径。

于 2010-04-05T13:22:27.803 回答
0

一种方法——如果数据是稳定的(例如,一旦插入就永远不会改变)是在插入时计算传递关系(例如,通过触发器或执行插入的应用程序)。

例如,您的表中有一个新列“start_ts”;插入记录时:

in_timestamp | out_timestamp | name  | in_id | out_id | in_server | out_server | status
timestamp3   | timestamp4    | data1 | id3   | id4    | my-server2   | my-server3 | success

...然后您的逻辑会自动使用 and 找到记录name=data1并将out_id=id3其克隆start_ts到新插入的记录中。您可能还需要围绕传播最后状态的一些特殊逻辑,具体取决于您如何计算这些传递值。

顺便说一句,您不必一定要查找前一个 (name=data1out_id=id3) 记录 - 您可以在处理时将值保留start_ts在数据记录的元数据本身中。

那么最终的报告就简单select start_ts, out_ts from T where out_server=others_server2了(当然就out_server和status来说更复杂,但仍然是一个简单的选择)

第二种选择当然是计算结果报告的更直接的循环 - 如果您不确定如何使用 SQL BFS 实现,请使用 google 或“stack”(现在这是一个公认的动词吗?)。

于 2010-04-05T11:16:54.080 回答
0
  • @其他读者:

    首先参考 Mark Byers 发布的第一个答案。我使用“回答”而不是“评论”他的帖子,因为我需要使用表格/链接等,这在评论答案时不可用。:)

  • @马克拜尔斯:

感谢您的链接......它真的帮助了我,我能够找出在服务器之间生成路径的方法......看看@我能做什么。

in_id   | in_timestamp  | out_timestmap | name  | hops_count    | path  |
id1     | timestamp1    | timestamp2    | data1 | 1             | {id1} |
id2     | timestamp2    | timestamp3    | data1 | 2             | {id1,id2} |
id3     | timestamp3    | timestamp4    | data1 | 3             | {id1,id2,id3} |
id4     | timestamp4    | timestamp2    | data1 | 4             | {id1,id2,id3,id4} |

* 使用 'in_id' 生成路径

我使用了以下查询...

WITH RECURSIVE foo AS
        (
        SELECT  t_alias1, 1 AS hops_count, ARRAY[in_id] AS hops
        FROM    log_parsing.log_of_sent_mails t_alias1
        WHERE   in_server = 'other-server1'
        UNION ALL
        SELECT  t_alias2, foo.hops_count + 1 AS hops_count, hops || in_id
        FROM    foo
        JOIN    log_parsing.log_of_sent_mails t_alias2
        ON      t_alias2.in_id = (foo.t_alias1).out_id 
        )
SELECT  (foo.t_alias1).in_id,
        (foo.t_alias1).name,
        (foo.t_alias1).in_timestamp,
        hops_count,
        hops::VARCHAR AS path
FROM    foo   ORDER BY   hops

但我还没有达到终极阶段。这是我最终希望得到的...

in_id   | in_timestamp  | out_timestmap | name  | hops_count    | path  |
id4     | timestamp1    | timestamp5    | data1 | 4             | {id1,id2,id3,id4}|

* 观察时间戳。它是必需的,因为我不希望客户知道内部基础设施。所以对他来说,timestamp1 和 timestamp5 之间的时间差才是最重要的。

任何线索我怎么可能实现它!?

ps 我也会尝试联系Quassnoi。:)

于 2010-04-08T11:31:28.267 回答