以下查询在大约五十万行的表上执行时间超过20秒:
SELECT images.id, images.user_id, images_locale.filename, extension, size, width, height, views, batch, source, status, images.created_at, images.category_id, title, short_description, long_description, alternate, slugs.name as slug, images_locale.slug_id, path_cache AS category_path, full_name, users.username
FROM images
JOIN images_locale ON images_locale.image_id = images.id JOIN slugs ON images_locale.slug_id = slugs.id JOIN categories_locale ON images.category_id = categories_locale.category_id JOIN users ON users.id = images.user_id
WHERE slugs.name = 'THE_SLUG_HERE' AND images.status = '1' AND images_locale.locale_id = 1 AND categories_locale.locale_id = 1
LIMIT 1
现在当我删除slugs.name = 'THE_SLUG_HERE' AND
时,我会在几毫秒内得到结果。
这是我的slug表:
CREATE TABLE `slugs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(250) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
`type` tinyint(4) NOT NULL,
`locale_id` smallint(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=3611900 DEFAULT CHARSET=utf8;
我尝试CREATE INDEX test_speed ON slugs(name)
,但它没有加快速度。
请帮忙。
修改
以下是EXPLAIN的结果:
答案 0 :(得分:1)
将所有条件移到连接的ON
子句中:
SELECT ...
FROM images
JOIN images_locale ON images_locale.image_id = images.id
AND images_locale.locale_id = 1
JOIN slugs ON images_locale.slug_id = slugs.id
AND slugs.name = 'THE_SLUG_HERE'
JOIN categories_locale ON images.category_id = categories_locale.category_id
AND categories_locale.locale_id = 1
JOIN users ON users.id = images.user_id
WHERE images.status = '1'
LIMIT 1
这样做的原因是WHERE
子句会过滤所有可能连接的结果,但是如果将条件移到ON
子句中,则会避免加入以下所有连接已经知道的行的表格不是。
这可以避免做数百万的不必要的连接!
答案 1 :(得分:0)
尝试更改您的联接顺序。从解释结果来看,它表明该索引只能将图像表剪切为1.4k记录。所以你的关节从那个数字开始。也许你可以用slug表启动关节(我假设名称是唯一的)并将名称条件过滤器放入连接的部分。
您可能还想调查复合键,以便所有使用的字段都可以在索引中。密钥扫描比文件扫描更快。
最后,看看你的mysql是如何配置的。它是否使用临时表进行查询。或者最糟糕的是,基于磁盘的临时表。
有点难以告诉我们我们不知道您的数据库的完整范围。例如,所有表的大小,为键设置的缓冲区数量,排序缓冲区等。