совокупный внутренний запрос SQL оптимизация - PullRequest
1 голос
/ 27 января 2020

У меня есть 3 таблицы:

create table users
    (
        user_id varchar(50),
        birth_year int,
        country varchar(50)
    )


create table notifications 
    (
        status varchar(50), 
        user_id varchar(50), 
        created_date datetime
    )

create table transactions
    (
        transaction_id varchar(50),
        user_id varchar(50),
        created_date datetime
    )

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

Я сделал следующее:

select q.country
, case when q.age <= 18 then '<= 18'
    when q.age <= 30 then '19 - 30'
    when q.age <= 45 then '31 - 45'
    when q.age <= 60 then '46 - 60'
    else '> 60' end as age_group
, AVG(q.prev_transactions*1.0) as avg_prev_transactions, AVG(q.post_transactions*1.0) as avg_post_transactions
from (
    select n.user_id, n.created_date, u.country, (2019 - u.birth_year) as age
    , count(distinct prev.transaction_id) as prev_transactions, count(distinct post.transaction_id) as post_transactions
    from notifications n
    left outer join transactions post on n.user_id = post.user_id and post.created_date > n.created_date and post.created_date < n.created_date + interval '7' day
    left outer join transactions prev on n.user_id = prev.user_id and prev.created_date < n.created_date and prev.created_date > n.created_date - interval '7' day
    left outer join users u on u.user_id = n.user_id
    where status = 'SENT'
    group by n.user_id, n.created_date, u.country, (2019 - u.birth_year)
    --order by n.user_id asc, n.created_date asc
    ) as q
group by q.country, case when q.age <= 18 then '<= 18'
    when q.age <= 30 then '19 - 30'
    when q.age <= 45 then '31 - 45'
    when q.age <= 60 then '46 - 60'
    else '> 60' end

Мне было интересно, есть ли способ сделать его более эффективным.

Спасибо

1 Ответ

0 голосов
/ 27 января 2020

Вероятно, возникли проблемы с двумя левыми соединениями в "транзакциях". Если имеется 30 предыдущих транзакций и 30 после транзакций, то эти два объединения, по существу, объединяются в декартовой системе, что создает 900 парных предварительных связей. Затем они уменьшаются до 30 с использованием DISTINCT. Но вы выполняете работу как по созданию, так и по удалению несерьезных строк.

Вы можете поместить их в подвыбор каждого, а не как объединения.

select n.user_id, n.created_date, u.country, (2019 - u.birth_year) as age,
    (select count(*) from transactions post on n.user_id = post.user_id and post.created_date > n.created_date and post.created_date < n.created_date + interval '7' day) as post_transactions,
...

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

...