1

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

我有一个包含 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

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

4

3 回答 3

5

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

由于您的分组依据是 Files_ID,因此您希望将 THOSE 分组。然后是 MIN(Date_From),所以它在第二个位置......然后最后是 Campaign_ID 符合非空的条件,这就是为什么......

如果您将所有广告系列 ID 放在首位,那太好了,将所有 NULL 排除在外……现在,您有 1,000 个广告系列,并且 Files_ID 跨越了许多广告系列,而且它们也跨越了许多日期,您会窒息的。

通过我投影的索引,首先通过 Files_ID,您已经订购了每个“files_id”以匹配您的组。然后,在其中,所有最早的日期都在索引列表的顶部……很好,几乎在那里,然后,按活动 ID。跳过可能存在的任何 NULL 并完成,进入下一个 Files_ID

希望这是有道理的——除非您有大量具有 NULL 值活动的条目。

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

于 2012-11-15T00:24:21.623 回答
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; 

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

于 2012-11-14T22:11:30.303 回答
1

我会创建一个覆盖索引(CAMPAIGN_ID、files_id、date_from)并检查该性能。我怀疑您的问题是由于分组 not 和 date_from 无法使用相同的索引。

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

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

于 2012-11-14T21:53:29.383 回答