удаление операций объединения из группового запроса - PullRequest
2 голосов
/ 04 июня 2019

У меня есть таблица, которая выглядит следующим образом:

usr_id  query_ts
12345   2019/05/13 02:06
123444  2019/05/15 04:06
123444  2019/05/16 05:06
12345   2019/05/16 02:06
12345   2019/05/15 02:06

, в которой содержится идентификатор пользователя, когда они запускали запрос.Каждая запись в таблице представляет этот идентификатор, выполняющий 1 запрос в заданную временную метку.

Я пытаюсь произвести это:

usr_id  day_1   day_2   …   day_30
12345   31       13           15
123444  23       41           14

Я хотел бы показать количество запросов, выполняемых каждый деньза последние 30 дней для каждого идентификатора, и если в этот день не было выполнено ни одного запроса, это будет 0.

Вот часть запроса, с которой я столкнулся,

SELECT
t1.usr_id,
case when t1.count_day_1 is null then 0 else t1.count_day_1 end as day_1,
case when t2.count_day_2 is null then 0 else t2.count_day_2 end as day_2
FROM

(SELECT usr_id, DAY(from_unixtime(unix_timestamp(query_ts ,"yyyy/MM/dd"), "yyyy-MM-dd")) as day_1,
        COUNT( DAY(from_unixtime(unix_timestamp(query_ts ,"yyyy/MM/dd"), "yyyy-MM-dd"))) as count_day_1
        FROM db.table
        WHERE
            DAY(from_unixtime(unix_timestamp(query_ts ,"yyyy/MM/dd"), "yyyy-MM-dd")) = 1
        AND
            from_unixtime(unix_timestamp(query_ts ,"yyyy/MM/dd"), "yyyy-MM-dd")
                BETWEEN date_sub(from_unixtime(unix_timestamp()), 30)
                AND from_unixtime(unix_timestamp())
        GROUP BY usr_id, day_1) t1

LEFT JOIN
(SELECT usr_id, DAY(from_unixtime(unix_timestamp(query_ts ,"yyyy/MM/dd"), "yyyy-MM-dd")) as day_2,
        COUNT( DAY(from_unixtime(unix_timestamp(query_ts ,"yyyy/MM/dd"), "yyyy-MM-dd"))) as count_day_2
        FROM db.table
        WHERE
            DAY(from_unixtime(unix_timestamp(query_ts ,"yyyy/MM/dd"), "yyyy-MM-dd")) = 2
        AND
            from_unixtime(unix_timestamp(query_ts ,"yyyy/MM/dd"), "yyyy-MM-dd")
                BETWEEN date_sub(from_unixtime(unix_timestamp()), 30)
                AND from_unixtime(unix_timestamp())
        GROUP BY usr_id, day_2) t2
ON (t1.usr_id = t2.usr_id)
ORDER BY t1.usr_id;

Это прекрасно работает, показывает количество запросов, выполняемых каждый день в течение первых 2 дней, и заменяет NULL на 0.

Проблема заключается в том, чтобы заставить это работать в течение всех 30 дней, я должен использовать 30 ЛЕВЫХ СОЕДИНЕНИЙ, которые тянут ~ 400 ГБ + памяти в кластере.

Есть ли более простой способ сделать это?

1 Ответ

2 голосов
/ 04 июня 2019

Попробуйте сделать это без объединения и используйте current_date или current_timestamp константы, а не unix_timestamp () в WHERE, эта функция не является детерминированной, и ее значение не является фиксированным для объема выполнения запроса, следовательно, предотвращает правильную оптимизацию запросов - с 2.0 она устарела в пользу константы CURRENT_TIMESTAMP:

select usr_id,
nvl(count(case when from_unixtime(unix_timestamp(query_ts ,"yyyy/MM/dd"), "dd") = 1 then 1 end),0) as day_1,
nvl(count(case when from_unixtime(unix_timestamp(query_ts ,"yyyy/MM/dd"), "dd") = 2 then 1 end),0) as day_2
...
from db.table
        WHERE
            from_unixtime(unix_timestamp(query_ts ,"yyyy/MM/dd"), "yyyy-MM-dd")
                BETWEEN date_sub(current_date, 30) AND current_date)
group by usr_id
...