【发布时间】:2016-07-19 12:00:55
【问题描述】:
我正在优化我的查询,发现了一些我无法理解的东西。
我正在使用以下查询来选择一堆类别,并将它们与包含类别旧别名和新别名的表中的别名相结合:
SELECT `c`.`id` AS `category.id`,
(SELECT `alias`
FROM `aliases`
WHERE category_id = c.id
AND `old` = 0
AND `lang_id` = 1
ORDER BY `id` DESC
LIMIT 1) AS `category.alias`
FROM (`categories` AS c)
WHERE `c`.`status` = 1 AND `c`.`parent_id` = '11';
parent_id 只有 2 个类别的值为 11,因此它应该从别名表中查找 2 个类别。
如果我使用EXPLAIN,它仍然说它必须处理 48 行。别名表也包含每个类别的 1 个条目(在这种情况下,它可以更多)。一切都已编入索引,如果我理解正确,它应该立即找到正确的别名。
现在奇怪的事情来了。当我不按条件中的类别比较别名,而是通过查询返回的类别 ID 手动比较别名时,它确实只处理 1 行,正如索引所预期的那样。
所以我将WHERE category_id = c.id 替换为WHERE category_id IN (37, 43) 并且查询变得更快:
我唯一能想到的是,子查询不是在查询结果上运行,而是在一些过滤完成之前运行。欢迎任何形式的解释或帮助!
编辑: 傻瓜,WHERE IN 不起作用,因为它没有做出独特的选择。但问题仍然存在!
创建表架构
CREATE TABLE `aliases` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`lang_id` int(2) unsigned NOT NULL DEFAULT '1',
`alias` varchar(255) DEFAULT NULL,
`product_id` int(10) unsigned DEFAULT NULL,
`category_id` int(10) unsigned DEFAULT NULL,
`brand_id` int(10) unsigned DEFAULT NULL,
`page_id` int(10) unsigned DEFAULT NULL,
`campaign_id` int(10) unsigned DEFAULT NULL,
`old` tinyint(1) unsigned DEFAULT '0',
PRIMARY KEY (`id`),
KEY `product_id` (`product_id`),
KEY `category_id` (`category_id`),
KEY `page_id` (`page_id`),
KEY `alias_product_id` (`product_id`,`alias`),
KEY `alias_category_id` (`category_id`,`alias`),
KEY `alias_page_id` (`page_id`,`alias`),
KEY `alias_brand_id` (`brand_id`,`alias`),
KEY `alias_product_id_old` (`alias`,`product_id`,`old`),
KEY `alias_category_id_old` (`alias`,`category_id`,`old`),
KEY `alias_brand_id_old` (`alias`,`brand_id`,`old`),
KEY `alias_page_id_old` (`alias`,`page_id`,`old`),
KEY `lang_brand_old` (`lang_id`,`brand_id`,`old`),
KEY `id_category_id_lang_id_old` (`lang_id`,`old`,`id`,`category_id`)
) ENGINE=InnoDB AUTO_INCREMENT=112392 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
【问题讨论】:
-
嗯?架构与
SELECT不匹配——status和parent_id在哪里? -
status和parent_id来自主表 (categories),而不是子查询(注意c别名)
标签: mysql indexing subquery explain