大表上的MySQL查询优化

时间:2012-07-26 21:46:29

标签: mysql optimization group-by average

我正在使用mysql查询一个表,该表有1200万个寄存器,这些寄存器是所述数据的一年。 查询必须选择某种数据(硬币,企业,类型等),然后为该数据的某些字段提供每日平均值,以便我们可以在之后绘制图表。 梦想能够实时做到这一点,所以响应时间不到10秒,但此刻它看起来并不明亮,需要4到6分钟。 例如,其中一个查询提出150k寄存器,每天拆分大约500个,然后我们使用AVG()和GroupBy平均三个字段(不在where子句中)。

现在,对于原始数据,查询是

SELECT 
`Valorizacion`.`fecha`, AVG(tir) AS `tir`, AVG(tirBase) AS `tirBase`, AVG(precioPorcentajeValorPar) AS `precioPorcentajeValorPar` 
FROM `Valorizacion` USE INDEX (ix_mercado2)
WHERE
(Valorizacion.fecha >= '2011-07-17' ) AND
(Valorizacion.fecha <= '2012-07-18' ) AND
(Valorizacion.plazoResidual >= 365 ) AND
(Valorizacion.plazoResidual <= 3650000 ) AND
(Valorizacion.idMoneda_cache IN ('UF')) AND
(Valorizacion.idEmisorFusionado_cache IN ('ABN AMRO','WATTS', ...)) AND
(Valorizacion.idTipoRA_cache IN ('BB', 'BE', 'BS', 'BU'))
GROUP BY `Valorizacion`.`fecha` ORDER BY `Valorizacion`.`fecha` asc;

248 rows in set (4 min 28.82 sec)

索引是按顺序

中的所有where子句字段进行的
(fecha, idTipoRA_cache, idMoneda_cache, idEmisorFusionado_cache, plazoResidual)

选择“where”寄存器,不使用group by或AVG

149670 rows in set (58.77 sec)

选择寄存器,分组和只进行计数(*)取决于平均值

248 rows in set (35.15 sec)

这可能是因为它不需要转到磁盘来搜索数据,但它直接从索引查询中获取。

因此,我想告诉我的老板“我很抱歉,但它无法完成”,但在此之前,我来找你们,问你们是否认为我可以采取一些措施来改善这一点。我认为我可以通过索引时间来改进搜索,将具有最大基数的索引移动到前面等等,但即使在那之后,为每个记录访问磁盘并且执行AVG所花费的时间似乎太多了。

有什么想法吗?

- 编辑,表格结构

CREATE TABLE `Valorizacion` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `idInstrumento` int(11) NOT NULL,
  `fecha` date NOT NULL,
  `tir` decimal(10,4) DEFAULT NULL,
  `tirBase` decimal(10,4) DEFAULT NULL,
  `plazoResidual` double NOT NULL,
  `duracionMacaulay` double DEFAULT NULL,
  `duracionModACT365` double DEFAULT NULL,
  `precioPorcentajeValorPar` decimal(20,15) DEFAULT NULL,
  `valorPar` decimal(20,15) DEFAULT NULL,
  `convexidad` decimal(20,15) DEFAULT NULL,
  `volatilidad` decimal(20,15) DEFAULT NULL,
  `montoCLP` double DEFAULT NULL,
  `tirACT365` decimal(10,4) DEFAULT NULL,
  `tipoVal` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
  `idEmisorFusionado_cache` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
  `idMoneda_cache` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
  `idClasificacionRA_cache` int(11) DEFAULT NULL,
  `idTipoRA_cache` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
  `fechaPrepagable_cache` date DEFAULT NULL,
  `tasaEmision_cache` decimal(10,4) DEFAULT NULL,
  PRIMARY KEY (`id`,`fecha`),
  KEY `ix_FechaNemo` (`fecha`,`idInstrumento`) USING BTREE,
  KEY `ix_mercado_stackover` (`idMoneda_cache`,`idTipoRA_cache`,`idEmisorFusionado_cache`,`plazoResidual`)
) ENGINE=InnoDB AUTO_INCREMENT=12933194 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

1 个答案:

答案 0 :(得分:1)

无论您尝试做什么,从12M记录中选择150K记录并对其执行聚合功能都不会很快。

您可能主要处理历史数据,因为您的示例查询是针对一年的数据。更好的方法可能是预先计算您的每日平均值并将它们放入单独的表中。然后,您可以查询这些表以获取报告,图表等。您需要决定何时以及如何运行此类计算,以便您无需再次对相同数据重新运行它们。

当您的要求是对数百万条历史记录进行分析和报告时,您需要考虑数据仓库方法http://en.wikipedia.org/wiki/Data_warehouse,而不是简单的数据库方法。