2012-07-26 49 views
3

我正在用mysql查詢一個有12百萬個寄存器的表,這些寄存器是上述數據的一年。 查詢必須選擇某種數據(硬幣,企業,類型等),然後爲該數據的某些字段提供每日平均值,因此我們可以在之後對其進行繪製。 夢想能夠實時做到這一點,所以響應時間不到10秒,但目前看起來並不明顯,因爲它需要4到6分鐘。 例如,其中一個querys提供了150k個寄存器,每天分割約500個,然後使用AVG()和GroupBy對三個字段(不在where子句中)進行平均。大表上的MySQL查詢優化

現在,原始數據,查詢

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) 

該指數的順序

(fecha, idTipoRA_cache, idMoneda_cache, idEmisorFusionado_cache, plazoResidual) 

選擇「其中」寄存器,而無需使用取得了所有的where子句領域group by或AVG

149670 rows in set (58.77 sec) 

並選擇寄存器,分組和僅做一個計數(*)istead平均花費

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 
+0

如果添加一個索引是一個選項(它會鎖定表格一段時間)嘗試添加這個'idMoneda_cache,idTipoRA_cache,idEmisorFusionado_cache,plazoResidual'(不知道「plazoResidual」或「fecha」應該是最後一個)。然後運行它(或「解釋」它)沒有'USE INDEX'。原因是MySQL只會使用索引到有範圍條件的字段(在您的情況下,您只使用索引中的「fecha」列)。 – Vatev 2012-07-26 21:54:11

+0

這很有道理,現在是下降到1分2秒。 行:193763.額外:使用where;使用臨時;使用filesort。 但是,放在網頁上仍然太慢= | – Jimmy 2012-07-26 22:12:35

+1

仍然不是很好用...你可以發佈'SHOW CREATE TABLE ...'(可能沒有任何不相關的列)和完整的'EXPLAIN'輸出 – Vatev 2012-07-26 22:17:21

回答

1

選擇150K記錄了12M的記錄,並執行它們聚合函數不會那麼快不管你做什麼。

由於您的示例查詢是針對一年的數據,因此您可能主要處理的是歷史數據。更好的方法可能是預先計算每日平均值並將它們放入單獨的表格中。然後,您可以查詢這些表格以獲取報告,圖表等。您需要決定何時以及如何運行此類計算,以便您不必在相同的數據上重新運行它們。

當您的要求是對數百萬條歷史記錄進行分析和報告時,您需要考慮數據倉庫方法http://en.wikipedia.org/wiki/Data_warehouse而不是簡單的數據庫方法。

+0

你完全正確,謝謝:) – Jimmy 2012-07-28 00:52:04