【问题标题】:Which indexes do I need to add to speed up this MYSQL JOIN/GROUP BY/HAVING query?我需要添加哪些索引来加速这个 MYSQL JOIN/GROUP BY/HAVING 查询?
【发布时间】:2011-06-24 08:04:34
【问题描述】:

当 current_vacature_response 包含 88k 条记录,daily_vacature_response 包含 10k 条记录时,执行以下查询大约需要 30 秒。使用 EXPLAIN 我得出的结论是,current_vacature_response 表中没有使用任何索引。我添加了一些基本索引,但似乎没有一个被使用。我需要设置什么样的索引来加速这个查询?

查询:

SELECT c.`stats_date` as `stats_date` 
    FROM `current_vacature_response` c 
    LEFT JOIN `daily_vacature_response` d ON (c.`stats_date` = d.`stats_date` )
    GROUP BY c.`stats_date`, d.`stats_date` 
    HAVING max(d.`last_stats_datetime`) IS NULL 
        OR MAX(d.`last_stats_datetime`) < MAX(c.`created_datetime`);

current_vacature_response 表定义:

CREATE TABLE `current_vacature_response` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `created_datetime` datetime NOT NULL,
  `site_id` tinyint(1) unsigned NOT NULL,
  `stats_date` date NOT NULL,
  `type` enum('typ1', 'type2') NOT NULL,
  `vacature` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `current_vacature_created_datetime` (`created_datetime`),
  KEY `current_vacature_response_vacature` (`vacature`),
  KEY `current_vacature_response_type` (`type`),
  KEY `current_vacature_stats_date` (`stats_date`)
) ENGINE=MyISAM AUTO_INCREMENT=88210 DEFAULT CHARSET=utf8;

daily_vacature_response 表定义:

CREATE TABLE `daily_vacature_response` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `contact` int(10) unsigned NOT NULL DEFAULT '0',
  `site_id` tinyint(1) unsigned NOT NULL,
  `spotlight_result` int(10) unsigned NOT NULL DEFAULT '0',
  `stats_date` date NOT NULL,
  `last_stats_datetime` datetime NOT NULL,
  `vacature` int(10) unsigned NOT NULL,
  `created_datetime` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `daily_vacature_response_key` (`site_id`,`vacature`,`stats_date`),
  KEY `daily_vacature_response_last_stats_datetime` (`last_stats_datetime`),
  KEY `daily_vacature_response_stats_date` (`stats_date`)
) ENGINE=MyISAM AUTO_INCREMENT=9802 DEFAULT CHARSET=utf8;

解释输出:

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: c
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 88209
        Extra: Using temporary; Using filesort
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: d
         type: ref
possible_keys: daily_vacature_response_stats_date
          key: daily_vacature_response_stats_date
      key_len: 3
          ref: reporting_development.c.stats_date
         rows: 99
        Extra: 

【问题讨论】:

  • 您只在HAVING子句中进行过滤,该子句在所有其他操作之后执行,因此使用索引为时已晚。您可以做的最好的事情是重写查询,使过滤在早期阶段(在 where 子句或连接条件中)执行。否则 MySQL 将始终必须扫描整个 current_vacature_response 表。所以唯一的解决方案是重写查询,但为了正确地做到这一点,请解释stats_date、created_datetime、last_stats_datetime。您能否提供一些示例输入和预期输出?
  • Tnx,我重写了一个更快的查询(4ms):SELECT c.stats_date FROM current_cv_response c GROUP BY c.stats_date HAVING MAX(c.created_datetime) NOT IN (SELECT MAX(d.last_stats_datetime) FROM daily_cv_response d WHERE d.stats_date = c.stats_date GROUP BY d.stats_date);

标签: mysql indexing


【解决方案1】:

尝试在daily_vacature_response(stats_date, last_stats_datetime) 上建立索引。

我怀疑它会产生巨大的影响,但这是最有可能的候选者。

另外,尝试稍微重写查询(可能在 MySQL 中不起作用,但值得一试):

GROUP BY c.`stats_date`, c.`created_datetime`, d.`stats_date` 
HAVING max(d.`last_stats_datetime`) IS NULL 
    OR max(d.`last_stats_datetime`) < c.`created_datetime`;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多