我应该能够自己回答一个问题,但我没有,而且我也没有在谷歌找到任何答案:
我有一个包含这种结构的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
我假设我生成了必要的密钥但是查询应该花那么长时间,是吗?
答案 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;
这应该有更好的性能,如果不起作用,临时表只能是选择。