Ok, quindi ho una tabella MySQL davvero mostruosa (900k records, 180 MB totali) e voglio estrarre dai sottogruppi i record con maggiore date_updated
e calcolare ponderata media in ciascun gruppo. Il calcolo viene eseguito per ~ 15 ore, e ho la netta sensazione che io sia facendo torto.SQL magic: la query non dovrebbe richiedere 15 ore, ma è
Innanzitutto, layout di tabella mostruosa:
category
element_id
date_updated
value
weight
source_prefix
source_name
Solo chiave qui è in element_id
(BTREE, ~ elementi 8k unici).
e calcolo processo:
Fai hash per ogni gruppo e sottogruppo.
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'
Io davvero non capisco questo clamore con hash, ma ha funzionato veloce in questo modo. La magia oscura, presumo.
Trova massima data per ogni sottogruppo
CREATE TEMPORARY TABLE `temp2` (INDEX (`subcat_hash`))
SELECT MAX(`date_updated`) AS `maxdate` , `subcat_hash`
FROM `temp1`
GROUP BY `subcat_hash`;
registrazione temp1 con temp2 per trovare i valori medi ponderati per le categorie
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`;
(ora che ho guardato attraverso di essa e scritto tutto giù, mi sembra che dovrei usare INNER JOIN in quest'ultima query (per evitare 900k * 900k temp table)).
Ancora, c'è un modo normale per farlo?
UPD: alcune foto per riferimento:
rimosso ImageShack morti collegamento
UPD: spiegare per soluzione proposta:
+----+-------------+-------+------+---------------+------------+---------+--------------------------------------------------------------------------------------+--------+----------+----------------------------------------------+
| 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 |
+----+-------------+-------+------+---------------+------------+---------+--------------------------------------------------------------------------------------+--------+----------+----------------------------------------------+
Ok, proverò a spiegare. Ci sono misurazioni in questa tabella. Ogni misura ha origine (identificata da prefisso + nome) e categoria. Ogni elemento può avere misurazioni in tutte le categorie o solo in alcune. Quello che voglio fare è trovare l'ultima misura per elemento da una fonte, quindi calcolare la media ponderata per elementi + categorie. Ci scusiamo per il mio inglese, btw - non la mia lingua principale: \ –
Post updated. Il valore data_updated * esattamente * è uguale per tutte le ultime misurazioni? O sono proprio nello stesso giorno? – Andomar
Sono solo gli ultimi per la stessa fonte ed elemento. Possono variare. –