Транзитивный SQL-запрос к той же таблице

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

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 «моих сервера». Оно отличается от ситуации к ситуации. например может быть задействовано 4 «моих сервера», скажем, для data2!

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

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

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


person MiKu    schedule 05.04.2010    source источник
comment
Как вы определяете «статус» в своем результате в случае, если есть смесь статусов?   -  person Mark Byers    schedule 05.04.2010
comment
'status' =› успешная доставка данных между двумя серверами, указанными в одной строке. :) Итак, если это успех для всего пути, то это в целом успешная доставка данных. :)   -  person MiKu    schedule 08.04.2010


Ответы (3)


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

person Mark Byers    schedule 05.04.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 и статуса, но все же один простой выбор)

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

person DVK    schedule 05.04.2010
comment
ПЕРВЫЙ ВАРИАНТ. Проблема генерации вычислений в памяти заключается в том, что каждый из этих журналов создается на разных «моих серверах», но каждый из этих «моих серверов» сохраняется в централизованной БД. Так что я могу представить себе распределенные вычисления в реальном времени, но я не настолько опытен, чтобы попробовать это... DB штука кажется мне немного возможной.. :D ВТОРОЙ ВАРИАНТ: Опять же, я хочу избежать этого @ app. причина уровня в том, что в БД есть огромный кусок данных. Я хочу не загружать все это в приложение, а затем обрабатывать. :) Поправьте меня, если я неправильно понял вас или ваши комментарии! :) - person MiKu; 08.04.2010

  • @Другие читатели:

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

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

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

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.

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

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

person MiKu    schedule 08.04.2010