mysql哪里+组很慢

时间:2012-11-14 21:47:53

标签: mysql group-by key

我应该能够自己回答一个问题,但我没有,而且我也没有在谷歌找到任何答案:

我有一个包含这种结构的500万行的表:

CREATE TABLE IF NOT EXISTS `files_history2` (
  `FILES_ID` int(10) unsigned DEFAULT NULL,
  `DATE_FROM` date DEFAULT NULL,
  `DATE_TO` date DEFAULT NULL,
  `CAMPAIGN_ID` int(10) unsigned DEFAULT NULL,
  `CAMPAIGN_STATUS_ID` int(10) unsigned DEFAULT NULL,
  `ON_HOLD` decimal(1,0) DEFAULT NULL,
  `DIVISION_ID` int(11) DEFAULT NULL,
  KEY `DATE_FROM` (`DATE_FROM`),
  KEY `FILES_ID` (`FILES_ID`),
  KEY `CAMPAIGN_ID` (`CAMPAIGN_ID`),
  KEY `CAMP_DATE` (`CAMPAIGN_ID`,`DATE_FROM`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

执行时

SELECT files_id, min( date_from )
FROM files_history2
WHERE campaign_id IS NOT NULL
GROUP BY files_id

查询的状态为“发送数据”超过八小时(然后我终止了该过程)。

这里的解释:

id  select_type     table           type    possible_keys           key     key_len     ref     rows        Extra
1   SIMPLE          files_history2  ALL     CAMPAIGN_ID,CAMP_DATE   NULL    NULL        NULL    5073254     Using where; Using temporary; Using filesort

我假设我生成了必要的密钥但是查询应该花那么长时间,是吗?

3 个答案:

答案 0 :(得分:5)

我建议使用不同的索引...索引(Files_ID,Date_From,Campaign_ID)......

由于您的分组在Files_ID上,因此您希望将其分组。然后是MIN(Date_From),这样就处于第二个位置......然后FINALLY将Campaign_ID限定为非null,这就是为什么......

如果你把所有的广告系列ID放在第一位,那就太棒了,把所有的空格都搞定了......现在,你有1000个广告系列,而且Files_ID跨越了很多广告系列,而且它们也跨越很多日期,你会窒息。

通过我正在预测的索引,首先是Files_ID,你已经订购了每个“files_id”以匹配你的组。然后,在其中,所有最早的日期都在索引列表的顶部...很好,几乎在那里,按广告系列ID。跳过可能存在的任何NULL并完成,转到下一个Files_ID

希望这是有道理的 - 除非您拥有具有NULL值广告系列的条目TON。

此外,通过使索引的所有3个部分与查询的条件和输出列匹配,它永远不必返回到数据的原始数据文件,它直接从索引获取所有内容。

答案 1 :(得分:1)

我创建了一个覆盖索引(CAMPAIGN_ID,files_id,date_from)并检查该性能。我怀疑你的问题是由于分组没有,而date_from无法使用相同的索引。

CREATE INDEX your_index_name ON files_history2 (CAMPAIGN_ID, files_id, date_from);

如果这样可行,您可以删除点索引CAMPAIGN_ID,因为它包含在复合索引中。

答案 2 :(得分:1)

由于聚合(函数MIN)以及分组,查询很慢。 其中一个解决方案是通过将聚合子查询从WHERE子句移动到FROM子句来更改查询,这将比您使用的方法快很多。

尝试以下:

SELECT f.files_id 
FROM file_history2 AS f 
JOIN ( 
SELECT campaign_id, MIN(date_from) AS datefrom 
FROM file_history2 
GROUP BY files_id 
) AS f1 ON f.campaign_id = f1.campaign_id AND f.date_from = f1.datefrom; 

这应该有更好的性能,如果不起作用,临时表只能是选择。