3

我有一个包含几百万行的表,我正在查询该表并想知道是否可以通过添加索引或任何东西来优化查询。

表架构:

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”语句的一部分。

4

3 回答 3

1

嗯,在这种情况下,关于 where 的索引可能会使事情变得更糟。索引会使事情变得更糟,因为查询会扫描索引,然后读取原始数据,但会乱序。如果数据大于内存,那么您可能会遇到不必要的缓存未命中。

一种解决方案是按日期对数据进行分区。

一种想法是在日期、国家和offer_id(一个索引,三个部分)上放置一个索引。

我不确定这是否可行。它解决了where问题,但只解决了一半group by

如果年份和月份是单独的列,则查询如下所示:

WHERE year >= 2012 and
GROUP BY country, offer_id, month, year

然后(年,月,国家,offer_id)上的索引可以满足where并且group by仅使用该索引。我不确定混合不同粒度的日期会发生什么。这导致按日期(可能在月份级别)进行分区,然后根据计数、offer_id 和日期进行索引。(有些数据库实际上支持功能索引,您可以在索引中使用年份(日期)。)

于 2013-01-14T19:22:25.993 回答
1

只看表结构:

  • 3 部分 由于 innodb 执行聚集索引的方式,主键使该表效率低下,而“id autoincrement not null primary key”可能会有所帮助。
  • 然后,添加“唯一(country,,campaign_iddate”约束以保持唯一性。
  • 此外,该组的索引:“key(国家,offer_id)”,可能还会将月份/年份添加到该索引中。
于 2013-01-14T19:31:16.007 回答
1

几种方法是可能的。

  • 您可以使用RANGE 分区来按年份划分表。

  • 您可以运行一个批次并存储每个月的总数,然后在totals表上运行查询。从它的名字来看aggregate_data,它似乎已经是批量生成的,它可能不会太困难或太昂贵。

  • 您可以尝试通过索引 on date, country, offer_id,但我认为INSERT如果您索引 on date, country, offer_id, impressions, clicks, leads, payout, revenue(这样,查询所需的所有数据都已经在索引中;不需要访问数据表。当然,这是有代价的——INSERT性能)。通过拆分dateyearmonth可以获得更好的结果,选择性能。

如果我遇到了你的问题,我会测试超级索引的性能(但要对整个应用程序进行良好的调整;不同的部分可能会遇到不同的性能影响);然后我会尝试使用批处理解决方案,即使这意味着有两个表并处理同步。

于 2013-01-14T19:28:02.983 回答