如何改进MySQL“填补空白”查询

时间:2015-07-23 13:06:58

标签: mysql

我有一张货币汇率表,我填写了欧洲央行公布的数据。该数据包含日期维度中的空白,例如假日。

CREATE TABLE `imp_exchangerate` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `rate_date` date NOT NULL,
  `currency` char(3) NOT NULL,
  `rate` decimal(14,6) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `rate_date` (`rate_date`,`currency`),
  KEY `imp_exchangerate_by_currency` (`currency`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

我还有一个数据仓库中的日期维度:

CREATE TABLE `d_date` (
  `date_id` int(11) NOT NULL,
  `full_date` date DEFAULT NULL,
  ---- etc.
  PRIMARY KEY (`date_id`),
  KEY `full_date` (`full_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

现在我试着填补这样的交换空白:

SELECT 
  d.full_date,
  currency,
  (SELECT rate FROM imp_exchangerate
   WHERE rate_date <= d.full_date AND currency = c.currency
   ORDER BY rate_date DESC LIMIT 1) AS rate
FROM
  d_date d,
  (SELECT DISTINCT currency FROM imp_exchangerate) c
WHERE
  d.full_date >=
    (SELECT min(rate_date) FROM imp_exchangerate
     WHERE currency = c.currency) AND
  d.full_date <= curdate()

解释说:

+------+--------------------+------------------+-------+----------------------------------------+------------------------------+---------+------------+------+--------------------------------------------------------------+
| id   | select_type        | table            | type  | possible_keys                          | key                          | key_len | ref        | rows | Extra                                                        |
+------+--------------------+------------------+-------+----------------------------------------+------------------------------+---------+------------+------+--------------------------------------------------------------+
|    1 | PRIMARY            | <derived3>       | ALL   | NULL                                   | NULL                         | NULL    | NULL       |  201 |                                                              |
|    1 | PRIMARY            | d                | range | full_date                              | full_date                    | 4       | NULL       | 6047 | Using where; Using index; Using join buffer (flat, BNL join) |
|    4 | DEPENDENT SUBQUERY | imp_exchangerate | ref   | imp_exchangerate_by_currency           | imp_exchangerate_by_currency | 3       | c.currency |  664 |                                                              |
|    3 | DERIVED            | imp_exchangerate | range | NULL                                   | imp_exchangerate_by_currency | 3       | NULL       |  201 | Using index for group-by                                     |
|    2 | DEPENDENT SUBQUERY | imp_exchangerate | index | rate_date,imp_exchangerate_by_currency | rate_date                    | 6       | NULL       |    1 | Using where                                                  |
+------+--------------------+------------------+-------+----------------------------------------+------------------------------+---------+------------+------+--------------------------------------------------------------+

MySQL需要多个小时才能执行该查询。有没有想法如何改善?我已尝试使用费率指数而没有任何明显的影响。

1 个答案:

答案 0 :(得分:0)

我现在有一段时间的解决方案:摆脱依赖的子查询。我不得不从多个角度思考多个地方,结果就是:

SELECT
  cd.date_id,
  x.currency,
  x.rate
FROM
  imp_exchangerate x INNER JOIN 
  (SELECT
    d.date_id,
    max(rate_date) as rate_date,
    currency
  FROM
    d_date d INNER JOIN
    imp_exchangerate ON rate_date <= d.full_date
  WHERE
    d.full_date <= curdate()
  GROUP BY
    d.date_id,
    currency) cd ON x.rate_date = cd.rate_date and x.currency = cd.currency

此查询现在在不到10分钟内完成,而原始查询则为多个小时。

获得的经验教训:避免使用MySQL中的依赖子查询,如瘟疫!