我有一个表中有几百万行,我正在查询表,想知道我是否可以通过添加索引或任何内容来优化查询。
表架构:
CREATE TABLE `aggregate_data` (
`impressions` int(10) unsigned NOT NULL,
`clicks` int(10) unsigned NOT NULL,
`leads` int(10) unsigned NOT NULL,
`date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`country` varchar(2) COLLATE utf8_bin NOT NULL,
`campaign_id` int(10) unsigned NOT NULL,
`payout` decimal(12,6) NOT NULL,
`revenue` decimal(12,6) NOT NULL,
`creative_id` int(10) unsigned NOT NULL DEFAULT '0',
`advertiser_id` int(11) unsigned NOT NULL DEFAULT '0',
`offer_id` int(11) unsigned NOT NULL DEFAULT '0',
`affiliate_id` int(11) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`country`,`campaign_id`,`date`),
KEY `date_added` (`date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
SQL查询:
SELECT
DATE_FORMAT(`date`, "%Y-%m-01 00:00:00") AS `date`,
offer_id,
country,
@sum_impressions := SUM(impressions),
@sum_clicks := SUM(clicks),
@sum_leads := SUM(leads),
@sum_payout := SUM(payout),
@sum_revenue := SUM(revenue)
FROM aggregate_data
WHERE `date` >= '2012-12-00 00:00:00'
GROUP BY country, offer_id, MONTH(`date`), YEAR(`date`)
当我做一个解释时,它总是告诉我它使用表中的所有行。
+----+-------------+----------------+------+---------------+------+---------+------+--------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+------+---------------+------+---------+------+--------+----------------------------------------------+
| 1 | SIMPLE | aggregate_data | ALL | date_added | NULL | NULL | NULL | 809715 | Using where; Using temporary; Using filesort |
+----+-------------+----------------+------+---------------+------+---------+------+--------+----------------------------------------------+
它使用“使用where”因为WHERE子句,“使用临时”因为group by和filesort因为group by(我认为)。
现在应该添加哪些其他索引或其他内容以优化此查询。随着行变大,运行需要几秒钟。
使用“@sum_impressions”之类的变量,因为此SELECT语句是“INSERT INTO ... ON DUPLICATE KEY UPDATE”语句的一部分。
任何帮助都将不胜感激。
答案 0 :(得分:1)
一种解决方案是按日期对数据进行分区。
一个想法是在date,country和offer_id(一个索引,三个部分)上放置一个索引。
我不确定这是否有效。它解决了where
问题,但只解决了group by
的一半问题。
如果年份和月份是单独的列,则查询类似于:
WHERE year >= 2012 and
GROUP BY country, offer_id, month, year
然后,(年,月,国家,offer_id)的索引可以仅使用索引来满足where
和group by
。我不确定在混合不同粒度的日期时会发生什么。这导致按日期(可能在月级别)进行分区,然后对count,offer_id和date进行索引。 (有些数据库实际上支持功能索引,您可以在索引中使用年份(日期)。)
答案 1 :(得分:1)
有几种方法可行。
您可以使用RANGE
partitioning按年划分表格。
您可以运行批处理并存储每个月的总计,然后在totals
表上运行查询。从aggregate_data
看,从名称来看,已经批量生成,可能不会太困难或太昂贵。
您可以尝试通过date, country, offer_id
建立索引,但如果您在{{{{}}上编入索引,我认为您可能会获得更好的结果(并浪费更多的磁盘空间以及INSERT
时间) 1}}(这样,查询所需的所有数据都已经在索引中;不需要访问数据表。当然这需要付出代价 - date, country, offer_id, impressions, clicks, leads, payout, revenue
表现。通过将INSERT
拆分为date
和year
,您可以获得更好的结果,选择性能明智。
如果我有你的问题,我会测试超级索引的表现(但是给整个应用程序一个好的安慰;不同的部分可能会遇到不同的性能影响);然后我会尝试使用批处理解决方案,即使它意味着有两个表并处理同步。
答案 2 :(得分:1)
只看表结构:
country
,campaign_id
,date
)“约束以保持唯一性。