Как оптимизировать выбор пар из одного столбца таблицы? - PullRequest
0 голосов
/ 26 марта 2020

Я использую PostgreSQL 9.5.19, DBeaver 6.3.4

У меня есть таблица, в которой одна строка - имя пользователя, место, которое он посетил, время, когда он там был

Мне нужно выбрать все пары мест, где находился какой-либо пользователь (если пользователь находился на месте a, и поместить место bi, нужно примерно так: пользователь, место a, место b, время на месте a, время на месте b)

Таблица прудов:

CREATE TABLE example.example (
    tm timestamp NOT NULL,
    place_name varchar NOT NULL,
    user_name varchar NOT NULL
);

Некоторые примеры данных:

INSERT INTO example.example (tm, place_name, user_name)
values
('2020-02-25 00:00:19.000', 'place_1', 'user_1'),
('2020-03-25 00:00:19.000', 'place_2', 'user_1'),
('2020-02-25 00:00:19.000', 'place_1', 'user_2'),
('2020-03-25 00:00:19.000', 'place_1', 'user_3'),
('2020-02-25 00:00:19.000', 'place_2', 'user_3');

Я пробую этот скрипт:

select 
   t.user_name    
  ,t.place_name as r1_place
  ,max(t.tm) as r1_tm
  ,t2.place_name as r2_place
  ,min(t2.tm) as r2_tm
from example.example as t
join example.example as t2 on t.user_name = t2.user_name 
                       and t.tm < t2.tm 
                       and t.place_name <> t2.place_name
where t.tm between '2020-02-25 00:00:00' and '2020-03-25 15:00:00' 
  and t2.tm between '2020-02-25 00:00:00' and '2020-03-25 15:00:00'
    group by t.user_name
       , t.place_name
       , t2.place_name

Похоже, он дает мне правильный результат, но он работает очень медленно. Могу ли я оптимизировать это как-нибудь?

Ответы [ 2 ]

0 голосов
/ 09 апреля 2020

Коллега помог мне создать оконную функцию:

select 
subq.*
,EXTRACT(EPOCH FROM (subq.next_tm - subq.tm)) as seconds_diff
from (
  select
    t1.user_name,
    t1.place_name,
    t1.tm,
    lead(t1.place_name) over w as next_place_name,
    lead(t1.tm) over w as next_tm
  from example.example as t1
  window w as (partition by t1.user_name order by tm asc)
)subq
where
  next_place_name is not null
  and next_tm is not null
  and place_name <> next_place_name
;
0 голосов
/ 26 марта 2020

Я бы предложил попробовать индексы. Для этого запроса:

select t.user_name, t.place_name as r1_place, max(t.tm) as r1_tm,
       t2.place_name as r2_place, min(t2.tm) as r2_tm
from schema.table t join
     schema.table t2
     on t.user_name = t2.user_name and
        t.tm < t2.tm and
        t.place_name <> t2.place_name
where t.tm between '2020-03-25 00:00:00' and '2020-03-25 15:00:00' and
      t2.tm between '2020-03-25 00:00:00' and '2020-03-25 15:00:00'
group by t.user_name, t.place_name, t2.place_name

Я бы предложил индекс для (tm, user_name, place_name) и (user_name, tm, place_name) - да, оба по одному для каждой ссылки.

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