有可能优化这个mysql查询吗?

时间:2013-01-14 19:14:57

标签: mysql sql mysqli

我有一个表中有几百万行,我正在查询表,想知道我是否可以通过添加索引或任何内容来优化查询。

表架构:

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

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:1)

嗯,这是一个案例,其中索引可能会使事情变得更糟。索引会使事情变得更糟,因为查询会扫描索引,然后读取原始数据,但不按顺序。如果数据大于内存,则可能会出现不必要的缓存未命中。

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

一个想法是在date,country和offer_id(一个索引,三个部分)上放置一个索引。

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

如果年份和月份是单独的列,则查询类似于:

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

然后,(年,月,国家,offer_id)的索引可以仅使用索引来满足wheregroup 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拆分为dateyear,您可以获得更好的结果,选择性能明智。

如果我有你的问题,我会测试超级索引的表现(但是给整个应用程序一个好的安慰;不同的部分可能会遇到不同的性能影响);然后我会尝试使用批处理解决方案,即使它意味着有两个表并处理同步。

答案 2 :(得分:1)

只看表结构:

  • 3部分主键使得该表效率低下,因为innodb的方式是聚簇索引,而“id autoincrement not null主键“可以帮助。
  • 然后,添加“唯一 (countrycampaign_iddate)“约束以保持唯一性。
  • 此外,该组的索引依据:“key(country,offer_id)”,可能还会将该月/年添加到该索引。