С правильными индексами, я подозреваю, это будет быстрее:
SELECT reg_date, AVG(du_flag) as rolling_retention_day1
FROM (SELECT date(u.reg_time) as reg_date,
(CASE WHEN EXISTS (SELECT 1
FROM dailyusers du
WHERE du.uid = u.uid AND
date(u.reg_time) + 1 <= du.day
)
THEN 1 ELSE 0
END) as du_flag
FROM users u
WHERE u.reg_time >= current_date - interval '30' day AND
u.reg_time < current_date + interval '1' day
)
GROUP BY reg_date;
Вам нужны индексы на users(reg_time)
и dailyusers(uid, day)
.Это предполагает, что uid
является уникальным в users
, что имеет смысл для меня.
Если вы действительно заботитесь о формате среднего, то вы можете сделать:
AVG(du_flag)::decimal(4, 2)
Это лучшее, что я могу сделать с запросом, который вы дали.Может быть лучший способ написать запрос.Я бы посоветовал вам задать другой вопрос с примерами данных, желаемыми результатами и объяснением того, что делает (или должен делать) запрос, если вам нужна помощь в этом.