Ok, entonces tengo una tabla MySQL realmente monstruosa (900k registros, 180 MB en total), y quiero extraer registros de subgrupos con mayor date_updated
y calculo ponderado promedio en cada grupo. El cálculo se ejecuta durante ~ 15 horas, y tengo una fuerte sensación de que estoy haciéndolo mal.SQL mágico - la consulta no debería tomar 15 horas, pero sí
En primer lugar, diseño de la mesa monstruosa:
category
element_id
date_updated
value
weight
source_prefix
source_name
Sólo clave aquí está en element_id
(BTREE, ~ elementos 8k únicas).
y cálculo de proceso:
picadillo Hacer para cada grupo y subgrupo.
CREATE TEMPORARY TABLE `temp1` (INDEX (`ds_hash`))
SELECT `category`,
`element_id`,
`source_prefix`,
`source_name`,
`date_updated`,
`value`,
`weight`,
MD5(CONCAT(`category`, `element_id`, `source_prefix`, `source_name`)) AS `subcat_hash`,
MD5(CONCAT(`category`, `element_id`, `date_updated`)) AS `cat_hash`
FROM `bigbigtable` WHERE `date_updated` <= '2009-04-28'
Realmente no entienden este alboroto con los hashes, pero funcionó más rápido de esta manera. La magia oscura, supongo.
Encuentra la fecha máxima para cada subgrupo
CREATE TEMPORARY TABLE `temp2` (INDEX (`subcat_hash`))
SELECT MAX(`date_updated`) AS `maxdate` , `subcat_hash`
FROM `temp1`
GROUP BY `subcat_hash`;
Ingreso Temp 1 con temp2 para encontrar valores medios ponderados para las categorías
CREATE TEMPORARY TABLE `valuebycats` (INDEX (`category`))
SELECT `temp1`.`element_id`,
`temp1`.`category`,
`temp1`.`source_prefix`,
`temp1`.`source_name`,
`temp1`.`date_updated`,
AVG(`temp1`.`value`) AS `avg_value`,
SUM(`temp1`.`value` * `temp1`.`weight`)/SUM(`weight`) AS `rating`
FROM `temp1` LEFT JOIN `temp2` ON `temp1`.`subcat_hash` = `temp2`.`subcat_hash`
WHERE `temp2`.`subcat_hash` = `temp1`.`subcat_hash`
AND `temp1`.`date_updated` = `temp2`.`maxdate`
GROUP BY `temp1`.`cat_hash`;
(ahora que me veía a través de él y escribió todo abajo, me parece que debería usar INNER JOIN en esa última consulta (para evitar la tabla de 900k * 900k temp)).
Aún así, ¿hay una forma normal para hacerlo?
UPD: un cierto cuadro para la referencia:
eliminado ImageShack muerto enlace
UPD: Vamos para solución propuesta:
+----+-------------+-------+------+---------------+------------+---------+--------------------------------------------------------------------------------------+--------+----------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------+---------------+------------+---------+--------------------------------------------------------------------------------------+--------+----------+----------------------------------------------+
| 1 | SIMPLE | cur | ALL | NULL | NULL | NULL | NULL | 893085 | 100.00 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | next | ref | prefix | prefix | 1074 | bigbigtable.cur.source_prefix,bigbigtable.cur.source_name,bigbigtable.cur.element_id | 1 | 100.00 | Using where |
+----+-------------+-------+------+---------------+------------+---------+--------------------------------------------------------------------------------------+--------+----------+----------------------------------------------+
Está bien, intentaré explicarlo. Hay medidas en esta tabla. Cada medición tiene fuente (identificada por prefijo + nombre) y categoría. Cada elemento puede tener medidas en todas las categorías, o solo en algunas. Lo que quiero hacer es encontrar la última medición para el elemento de una fuente, luego calcular el promedio ponderado de los elementos + categorías. Lo siento por mi inglés, por cierto, no es mi idioma principal: \ –
Publicada actualización. ¿La fecha_updated * exactamente * es igual para todas las últimas mediciones? ¿O solo están en el mismo día? – Andomar
Son los últimos para la misma fuente y elemento. Ellos pueden variar –