[英]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.