[英]MySQL sorting with Using temporary; Using filesort
这是我要启动的查询:
SELECT c.creative_id, c.creative_title, c.creative_image_name, c.gravity, c.ad_strength
FROM creatives AS c
INNER JOIN term_relationships AS tr ON c.creative_id = tr.creative_id
WHERE tr.term_id
IN ( 14, 1, 50, 76, 104 )
GROUP BY c.creative_id
HAVING COUNT(tr.term_id ) =5
ORDER BY c.gravity ASC
LIMIT 30;
这是此查询的EXPLAIN
输出:
这是creatives
表结构:
CREATE TABLE `creatives` (
`creative_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`scraper_id` bigint(20) unsigned DEFAULT NULL,
`creative_title` varchar(255) NOT NULL,
`creative_image_name` varchar(255) DEFAULT NULL,
`image_attrib` varchar(12) DEFAULT NULL,
`original_image_name` varchar(255) DEFAULT NULL,
`creative_subtext` varchar(255) DEFAULT NULL,
`dest_url` varchar(2083) NOT NULL,
`lp_url` varchar(2083) NOT NULL,
`lp_image_name` varchar(255) DEFAULT NULL,
`lp_image_flag` tinyint(1) unsigned NOT NULL DEFAULT '0',
`creative_first_seen` date NOT NULL,
`creative_last_seen` date NOT NULL,
`daily_ad_count` int(5) unsigned NOT NULL,
`ad_strength` int(11) unsigned NOT NULL,
`prev_ad_strength` int(11) unsigned DEFAULT NULL,
`gravity` int(11) unsigned DEFAULT NULL,
PRIMARY KEY (`creative_id`),
KEY `gravity` (`gravity`)
) ENGINE=InnoDB AUTO_INCREMENT=173037591 DEFAULT CHARSET=utf8
我担心Using temporary; using filesort
在另一列上同时使用GROUP BY
和ORDER BY
启动时,请Using temporary; using filesort
。 如果删除ORDER BY
,则临时和文件排序将消失,查询运行会非常快。
我不明白的是,为什么mysql需要临时表,为什么不能先在filter +按c.gravity
排序,然后将结果表分组并根据HAVING
子句进行过滤。 过滤后的表格将按c.gravity
正确排序,因为重力值在分组并具有过滤器后保持不变。
我试过的
选择没有ORDER BY
所有内容,将其包装到子查询中,然后再次加入到creatives
表中-使用临时,文件排序和缓慢的结果相同
试图添加FORCE USE INDEX FOR ORDER BY (gravity)
并且它没有任何改变。 EXPLAIN
和执行时间保持不变。
更新 :问题已由@Rick回答,并且使用他的相关子查询并且不使用GROUP BY
确实更快。 我在这里为查询添加EXPLAIN
输出:
以及带有新创建索引的SHOW CREATE TABLE term_relationships
的输出:
@Rick还有一个问题:为什么我们需要用c3
进行外部查询? 似乎仅仅是再加入一个creatives
,只是为了从其他列中获取值并通过重力对记录进行排序。 但是,它们已经使用内部查询进行了排序,我们可以轻松地在c1
添加缺少的列,从而实现:
SELECT c1.creative_id,c1.creative_title,c1.creative_image_name,c1.gravity, c1.ad_strength
FROM creatives AS c1
WHERE
( SELECT COUNT(*)
FROM term_relationships
WHERE c1.creative_id = creative_id
AND term_id IN ( 14, 1, 50, 76, 104 )
) = 5
ORDER BY c1.gravity ASC
LIMIT 30;
我的理解正确吗,或者我在查询中遗漏了什么?
临时表和文件排序本身不是反派。 它们是如此庞大。
这可能看起来更复杂,但是可能更快:
SELECT c3.creative_id,
c3.creative_title, c3.creative_image_name,
c3.gravity, c3.ad_strength
FROM
( SELECT creative_id
FROM creatives AS c1
WHERE
( SELECT COUNT(*)
FROM term_relationships
WHERE c1.creative_id = creative_id
AND term_id IN ( 14, 1, 50, 76, 104 )
) = 5
ORDER BY c1.gravity ASC
LIMIT 30
) AS c2
JOIN creatives c3 USING (creative_id)
ORDER BY c3.gravity
如果碰巧对内部查询使用INDEX(gravity)
,则它将在找到具有全部5个事务的30行后停止。 如果它生成一个tmp表,它将只有30行-比原始查询要好得多。 另请注意,tmp表将更窄-仅creative_id
在其中。 最后,它返回到creatives
以获取其余所需的列。 最后,将有另一种排序方式,但只有30行。
此外,“文件排序”在RAM中通常是非常快速的排序,而不是真正的“文件”排序。 我很确定我的查询不会在磁盘上。
term_relationships
需要以下综合索引: INDEX(creative_id, term_id)
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.