Target - Day_1 Rolling retention in %
Questions:
1) how can i speed up this query?
2) this conversation to numeric is slow down query?
3) do i have any other options to round() it somehow else? or it's optimal?
Query:
SELECT date(reg_time), round(CAST(count(DISTINCT du.uid) / count(DISTINCT users.uid)::float * 100 AS numeric), 2) AS rolling_retention_day1
FROM users
LEFT JOIN dailyusers du
ON users.uid = du.uid
AND date(reg_time) BETWEEN current_date - interval '30' DAY AND current_date
AND date(reg_time) + 1 <= day
GROUP BY date(reg_time);
reg_time
is enclosed with date function.
if reg_time
is an indexed column, enclosing reg_time with date function breaks indexed search. You need to consider not to use date(reg_time)
you can also identify your query issues by using SQL Explain Plan
With the right indexes, I suspect this will be faster:
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;
You want indexes on users(reg_time)
and dailyusers(uid, day)
. This assumes that uid
is unique in users
, which makes sense to me.
If you really care about the format of the average, then you can do:
AVG(du_flag)::decimal(4, 2)
This is the best I can do with the query you have given. There may be a better way to write the query. I would suggest you ask another question with sample data, desired results, and an explanation of what the query is doing (or supposed to be doing), if you want help with that.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.