Postgres проверяет перекрытие диапазона меток времени в строках таблицы - PullRequest
0 голосов
/ 15 октября 2018

У нас есть таблица Postgres (материализованное представление), содержащая около 2 миллионов строк с такими столбцами, как:

  • start_time (timestampz) - имеет индекс
  • end_time (timestampz) - имеет индекс

Для каждой строки в таблице мы хотели бы добавить столбец результата, который содержит:

  • 1, если диапазон времени начала и окончания строки перекрывается с любым другимстрока
  • 0, если диапазон времени начала и конца строки не перекрывается с какой-либо другой строкой

Какой эффективный подход был бы для обозначения каждой строки как перекрывающейся (1 или 0)?

РЕДАКТИРОВАТЬ:

Ожидаемый результат будет выглядеть примерно так:

  • row_id
  • has_overlap - логическое или int (1 или 0)

1 Ответ

0 голосов
/ 15 октября 2018

Я не думаю, что будет действительно быстрое решение для этого, так как оно требует сравнения каждой строки в таблице с каждой другой строкой в ​​таблице (или, по крайней мере, с каждой другой строкой в ​​указанном диапазоне).

Предполагая, что столбец первичного ключа вашей таблицы называется id, вы можете использовать функцию диапазона Postgres для проверки перекрывающихся строк:

with check_period (check_range) as (
   values ( tstzrange(timestamptz '2018-10-01 00:00:00', timestamptz '2018-10-14 20:15:00') )
)
select id, 
       start_Time, 
       end_time, 
       exists (select *
        from the_table t2
           cross join check_perioud
        where t2.id <> t1.id 
        and tstzrange(t1.start_time, t1.end_time) && tstzrange(t2.start_time, t2.start_time)
        and tstzrange(t2.start_time, t2.start_time) <@ check_range
       ) has_overlapping_rows
from the_table t1
  cross join check_period
where tstzrange(t1.start_time, t1.end_time) <@ check_range;

CTE check_periodтолько там, так что значения для периода времени, который вы хотите проанализировать, не повторяются.Если вам не нужно повторять их, вы можете удалить их:

select id, 
       start_Time, 
       end_time, 
       exists (select *
        from the_table t2
        where t2.id <> t1.id 
        and tstzrange(t1.start_time, t1.end_time) && tstzrange(t2.start_time, t2.start_time)
        and tstzrange(t2.start_time, t2.start_time) <@ tstzrange(timestamptz '2018-10-01 00:00:00', timestamptz '2018-10-14 20:15:00')
       ) has_overlapping_rows
from the_table t1
where tstzrange(t1.start_time, t1.end_time) <@ tstzrange(timestamptz '2018-10-01 00:00:00', timestamptz '2018-10-14 20:15:00');

Чтобы сделать это быстрым, вам нужно создать индекс в диапазоне временных отметок:

create index on the_table( (tstzrange(start_time, end_time), id );

Вы можете расширить приведенный выше запрос, чтобы он возвращал количество перекрывающихся строк, а не флаг истины / ложи:

select id, 
       start_Time, 
       end_time, 
       (select count(*)
        from the_table t2
        where t2.id <> t1.id 
        and tstzrange(t1.start_time, t1.end_time) && tstzrange(t2.start_time, t2.start_time)
        and tstzrange(t2.start_time, t2.start_time) <@ tstzrange(timestamptz '2018-10-01 00:00:00', timestamptz '2018-10-14 20:15:00')
       ) has_overlapping_rows
from the_table t1
where tstzrange(t1.start_time, t1.end_time) <@ tstzrange(timestamptz '2018-10-01 00:00:00', timestamptz '2018-10-14 20:15:00');

Однако для строк, имеющих много перекрывающихся строк, это будет медленнее, поскольку силы count(*)база данных для проверки всех перекрывающихся строк.Решение exists() может остановиться на первой найденной строке.

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