We have 2 SQL queries:
- Get active campaigns (234 rows, 0.0007 seconds)
SELECT id FROM campaigns WHERE campaigns.is_active = 1
- Get today's clicks for a user (17 rows, 0.0772 seconds)
SELECT id, campaign_id FROM clicks WHERE user_id = 1 AND created > '2022-06-23 00:00:00'
Both are fast and return a small number of rows.
Now I combine both to get active campaigns + amount of clicks today for a user:
SELECT count(clicks.id),
campaigns.id
FROM campaigns
LEFT JOIN clicks
ON ( clicks.campaign_id = campaigns.id
AND clicks.user_id = 1
AND clicks.created > '2022-06-23 00:00:00')
WHERE campaigns.is_active = 1
GROUP BY campaigns.id
Returns 234 rows in 8 seconds runtime.
Getting the campaign list (234 rows) takes 0.0007. Getting the clicks list (17 rows) takes 0.0772 seconds. But to assign the 17 clicks to the 234 campaigns suddenly takes 8 seconds? Why is it so slow? How can I fix it?
If I change from LEFT JOIN to INNER JOIN it takes only 0.09 seconds, but it's not the return I need.
The clicks table has around 21m rows with 50k new rows a day. It has a single index on each of these columns: user_id, campaign_id, created
CREATE TABLE:
CREATE TABLE `clicks` (
`id` int(11) UNSIGNED NOT NULL,
`user_id` int(7) UNSIGNED NOT NULL,
`campaign_id` int(11) UNSIGNED NOT NULL,
`created` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
ALTER TABLE `clicks`
ADD PRIMARY KEY (`id`),
ADD KEY `user_id` (`user_id`),
ADD KEY `campaign_id` (`campaign_id`),
ADD KEY `created` (`created`);
CREATE TABLE `campaigns` (
`id` int(11) UNSIGNED NOT NULL,
`is_active` tinyint(4) NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
ALTER TABLE `campaigns`
ADD PRIMARY KEY (`id`),
ADD KEY `is_active` (`is_active`);
