I have this table - 'product-usage'. The columns in this table are id, rank, product_id, checked_at (timestamp). I am trying to add another column (timestamp) to this table called 'last_inactive' and retroactively fill that column. The logic for this is 1) Find created_at for the immediate next entry for same product_id (ordered by rank) 2) Take that timestamp and subtract 1 seconds and use that timestamp to fill the current column and go on 3) If the next row does not exist, use now() as the value for last_inactive
I have tried the following to get the desired result
SELECT *,
coalesce(
date_sub(
(SELECT checked_at
FROM product_usage p2
WHERE p2.rank > p.rank
and p.product_id=p2.product_id
group by id, product_id, created_at
ORDER BY product_id, rank ASC
LIMIT 1 OFFSET 0),
INTERVAL 1 second),
now()
)
as valid_until
FROM product_usage p
where p.product_id = '1111111';
This query works for this particular product_id but it takes about 2-3 seconds per product_id and there are about 20k distinct product_ids I want this to work for. Is there anything I can do to make this faster?
You do not need the aggregation in the subquery. So try this:
SELECT pu.*,
coalesce(date_sub( (SELECT pu2.checked_at
FROM product_usage pu2
WHERE pu2.rank > pu.rank AND
pu2.product_id = pu.product_id
ORDER BY pu2.rank ASC
LIMIT 1 OFFSET 0
), INTERVAL 1 second
), now() ) as valid_until
FROM product_usage pu
WHERE pu.product_id = 1111111; -- looks like a number so removed the single quotes
Then for this, you want an index on product_usage(product_id, rank, created_at)
.
Of course, in MySQL 8+, you would just use lead()
.
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.