【发布时间】:2020-10-27 22:40:22
【问题描述】:
尺寸:
- 广告系列:3k 行(200 行,campaign.is_active = 1)
- 链接:20k 行(4k 行,links.status = 1 // 500 行,links.status = 1 AND campaign.is_active = 1)
- 点击次数:1000 万行(50k 次创建 > '2020-10-25 00:00:00')
此查询运行 2 秒
SELECT links.id, COUNT(clicks.id)
FROM links
INNER JOIN campaigns ON campaigns.id = links.campaign_id
AND campaigns.is_active = 1
LEFT JOIN clicks ON clicks.link_id = links.id
WHERE links.status = 1
AND clicks.created > '2020-10-25 00:00:00'
GROUP BY links.id
当我删除以下行时,它只运行 0.13 秒(快 15 倍)
AND campaigns.is_active = 1
campaigns.is_active 上有一个索引。 还尝试在 2 列(campaigns.id + campaign.is_active)上设置索引,但没有帮助。
“campaigns.is_active”只包含 0 或 1。campaigns 表很小,campaigns.is_active 条件实际上减少了行数。所以它应该加快查询速度。
为什么会因为这种情况需要这么长时间?如何解决?
如果我要删除活动的 JOIN,而是将 links.campaign_id 添加到 SELECT 字段,然后在附加查询中查询每个返回的活动 ID,例如“SELECT is_active FROMcampaign WHERE id = ?" 它仍然会更快,因为这样的查询是 0.000x。根据我的经验,当 2 次查询速度更快时,这通常意味着第一次查询没有得到最大程度的优化。
结构
CREATE TABLE `campaigns` (
`id` int(11) UNSIGNED NOT NULL,
`is_active` tinyint(4) NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `clicks` (
`id` int(11) UNSIGNED NOT NULL,
`link_id` int(11) UNSIGNED NOT NULL,
`created` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `links` (
`id` int(11) UNSIGNED NOT NULL,
`campaign_id` int(8) UNSIGNED NOT NULL,
`status` tinyint(4) NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `campaigns`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `id_isactive` (`id`,`is_active`),
ADD KEY `is_active` (`is_active`)
ALTER TABLE `clicks`
ADD PRIMARY KEY (`id`),
ADD KEY `link_id` (`link_id`),
ADD KEY `created` (`created`)
ALTER TABLE `links`
ADD PRIMARY KEY (`id`),
ADD KEY `campaign_id` (`campaign_id`),
【问题讨论】:
-
感谢您的 cmets。添加了缺失的信息。还添加了我删除的聚合函数以简化对 stackoverflow 的查询
-
阅读完此stackoverflow.com/tags/query-performance/info 请edit 您的问题提供更多信息。而且,
clicks.created上的过滤器会将您的 LEFT JOIN 变成普通的内部 JOIN。 -
EXPLAIN 暗示数据集比您建议的要小,但也许我遗漏了一些东西。顺便说一句,我认为innodb悄悄地将pk添加到所有索引的末尾,所以
(id,is_active)中的id有些多余 -
索引一个真/假或1/0列是不值得的,因为索引的选择性会很低,mysql无法使用它!
-
@Shadow,视情况而定。如果 90% 的行是
false并且您使用true搜索 10% 的行,那很好。但是,如果您假设这两个值分配得更均匀,那么您是对的,那么它就没有那么有效了。
标签: mysql sql query-performance