Транзитивный SQL-запрос к той же таблице - PullRequest
4 голосов
/ 05 апреля 2010

Эй. рассмотрим следующую таблицу и данные ...

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
  • Приведенные выше данные представляют собой журнал потока выполнения некоторых данных на серверах.
  • например. некоторые данные перетекли из какого-то «внешнего сервера1» в группу «моих серверов» и, наконец, в «другие серверы2».

Вопрос:

1) Мне нужно передать этот журнал в представительной форме клиенту, где ему не нужно ничего знать о группе «моих серверов». Все, что я должен дать, это метка времени данных, поступивших в мою инфраструктуру, и когда они ушли; переход к следующей информации.

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

Я хочу написать sql для того же! Может кто-нибудь помочь? ПРИМЕЧАНИЕ: не может быть 3 «моих серверов» все время. Это отличается от ситуации к ситуации. например скажем, для «data2!» может быть задействовано 4 «my-server»!

2) Есть ли другие альтернативы SQL? Я имею в виду сохраненные процы / etc?

3) Оптимизации? (Количество записей огромно! На сегодняшний день оно составляет около 5 миллионов в день. И мы должны показывать записи, возраст которых не превышает одну неделю.)

Заранее СПАСИБО ЗА ПОМОЩЬ! :)

Ответы [ 4 ]

2 голосов
/ 08 апреля 2010
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
1 голос
/ 05 апреля 2010

Ваша таблица имеет иерархическую структуру (списки смежности). Это можно эффективно запросить в PostgreSQL v8.4 и более поздних версиях, используя рекурсивные CTE. Quassnoi написал сообщение в блоге о том, как его реализовать. Это довольно сложный запрос, который вам нужно написать, но он хорошо объясняет его примерами, очень похожими на то, что вам нужно. Особенно, если вы посмотрите на свой последний пример, он демонстрирует запрос, а затем получает полный путь от первого узла к последнему, используя массив.

0 голосов
/ 08 апреля 2010
  • @ Другие читатели:

    См. Первый ответ, опубликованный Марком Байерсом первым. Я использовал «отвечать», а не «комментировать» его пост, так как мне нужно было использовать таблицы / ссылки и т. Д., Которые недоступны при комментировании ответов. :)

  • @ Марк Байерс:

Спасибо за ссылку ... Это действительно помогло мне, и я смог выяснить способ создания пути между серверами ... Посмотрите, что я смог сделать.

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}|

* соблюдайте отметку времени. Это необходимо, так как я не хочу, чтобы клиент знал о внутренней инфраструктуре. Поэтому для него важен временной интервал между отметкой времени1 и отметкой времени5.

Любая подсказка, как, возможно, я мог бы достичь этого !?

p.s. Я бы тоже попытался связаться с Quassnoi . :)

0 голосов
/ 05 апреля 2010

Один из способов сделать это - если данные являются СТАБИЛЬНЫМИ (например, никогда не меняются при вставке), это вычислить транзитивные отношения на лету (например, через триггер или приложение, которое выполняет вставку)во время вставки.

Например, у вас есть новый столбец "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

... тогда ваша логика автоматически находит запись с name=data1 и out_id=id3 и клонирует ее start_ts во вновь вставленную запись.Вам также может понадобиться некоторая специальная логика для распространения последнего статуса, в зависимости от того, как вы вычисляете эти переходные значения.

Кстати, вам не обязательно искать предыдущую (name=data1 и out_id=id3) запись -вы можете сохранить значение start_ts в самих метаданных записи данных во время обработки.

Тогда конечный отчет будет просто select start_ts, out_ts from T where out_server=others_server2 (конечно, более сложным с точки зрения out_server и status, но все же одним простымselect)

Второй вариант - это, конечно, более простой цикл, вычисляющий итоговый отчет - google или "stack" (это уже принятый глагол?) для реализаций SQL BFS, если вы 'Вы не уверены, как.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...