2016-09-20 3 views
1

Я запрашиваю схему веб-трафика, чтобы определить, какие визиты являются исходными и какие возвращаются.Оптимальный запрос для dense_rank, чтобы найти кратные

У меня есть две таблицы СЕССИЯ И АЛИАС.

CREATE TABLE alias (
    person_id vachar(24), 
    alias varchar(24) 
) 

CREATE TABLE session (
    session_id vachar(24), 
    alias varchar(24) -- FK to alias 
    last_seen timestamp 
) 

Таблица сеансов представляет веб-визиты для псевдонимов, а таблица псевдонима содержит псевдонимы для человека. Я пытаюсь создать представление о сеансе, которое позволит мне отметить сеанс как «Первый визит» лицом или «Возврат посетителя» лицом (отсюда и присоединиться к псевдониму ниже).

Решение, которое я имею до сих пор, использует функцию окна с dense_rank следующим образом.

CREATE VIEW session_augmented as (
    SELECT S.session_id, S.last_seen, .... 
    CASE 
     WHEN dense_rank() 
      OVER (partition by A.person_id COLLATE "C" ORDER by S.last_seen) = 1 
     THEN 'First Visit' 
     ELSE 'Return Visit' 
    END as visit_type 
    FROM session S 
    JOIN alias A ON (S.person_alias = A.alias) 

) 

Я создал индексы, охватывающие диапазон запросов, включая соединение выше.

В приведенном ниже пояснении показана проверка Seq Scan на сеансе, даже если столбец person_alias индексирован. Ниже приведено объяснение: https://explain.depesz.com/s/2LJ

Запрос выполняется медленнее, чем я хотел бы, есть ли способ оптимизации? Есть ли лучший подход, который достигает результата, который я получил?

ответ

1

Ранг, Dense Rank и все, что связано с заказом, будут средним случаем O (n log n), который для очень больших наборов данных может стать довольно репрессивным. В этом случае, я думаю, вы можете уйти с аналитической функцией min, которая должна быть лучшим, худшим и средним случаем O (n).

SELECT S.session_id, S.last_seen, .... 
CASE 
    WHEN min (S.last_seen) 
     over (partition by a.person_id) = s.last_seen 
    THEN 'First Visit' 
    ELSE 'Return Visit' 
END as visit_type 
FROM session S 
JOIN alias A ON (S.person_alias = A.alias) 

Хотя я сомневаюсь, что это имеет значение для обстоятельств, описанных вами, если бы это было теоретически возможно для человека, чтобы войти дважды в одно и то же время, то это потерпит неудачу, потому что он вернется две записи. Тем не менее, ваш запрос будет страдать от одной и той же проблемы, и снова я не думаю, что это возможно - я просто подумал, что приведу его к вашему вниманию.

Для того, что стоит оконных функций, определенно есть путь. Единственная разумная альтернатива, которую я вижу, - это написать обертку на каком-то языке программирования. Я сомневаюсь, что вы увидите значительное улучшение по сравнению с функцией min.

+0

Интересное решение. Однако на самом деле это было не так быстро, как в исходном вопросе. – maxTrialfire

+0

Виновник по-прежнему относится к типу: https://explain.depesz.com/s/ZTO – maxTrialfire

+0

Фактически, добавив некоторые индексы, я смог получить мой первоначальный запрос для выполнения лучших результатов: https://explain.depesz.com/s/m5E – maxTrialfire

Смежные вопросы