1

以下查询在大约 50 万行的表上执行需要 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 的结果:

<code>EXPLAIN</code> 的结果

4

2 回答 2

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子句中,就可以避免为您已经知道不需要的行连接所有下表。

这可以避免进行数百万次不必要的连接!

于 2012-10-08T01:23:05.650 回答
0

尝试更改您的连接顺序。从解释结果可以看出,索引只能将images表切割到1.4k条记录。所以你的关节是从那个数字开始的。也许您可以使用 slug 表(我假设名称是唯一的)开始连接,然后将名称条件过滤器放入连接的 on 部分。

您可能还想研究复合键,以便所有使用的字段都可以在索引中。键扫描比文件扫描快。

最后,看看你的mysql是如何配置的。是否使用临时表进行查询。或者最糟糕的是,基于磁盘的临时表。

很难说因为我们不知道您数据库的全部范围。例如,所有表的大小、为键设置的缓冲区数量、排序缓冲区等。

于 2012-10-09T01:03:20.943 回答