Sto lavorando a uno schema per un sistema di analisi che tiene traccia dei tempi di utilizzo e vi è la necessità di vedere il tempo totale di utilizzo in un determinato intervallo di date.
Per fare un semplice esempio, questo tipo di query verrebbe eseguito spesso:
select sum(diff_ms) from writetest_table where time_on > ("2015-07-13 15:11:56");
Questa query richiede in genere circa 7 secondi su una tabella fortemente popolata. Ha ~ 35 milioni di righe, MyISAM su MySQL in esecuzione su Amazon RDS (db.m3.xlarge).
Sbarazzarsi della clausola WHERE fa sì che la query richieda solo 4 secondi e l'aggiunta di una seconda clausola (time_off> XXX) aggiunge altri 1,5 secondi, portando il tempo di query a 8,5 secondi.
Dal momento che so che questi tipi di query verranno comunemente eseguiti, vorrei ottimizzare le cose in modo che siano più veloci, idealmente inferiori a 5 secondi.
Ho iniziato aggiungendo un indice su time_on, e sebbene questo abbia velocizzato drasticamente una query WHERE "=", non ha avuto alcun effetto sulla query ">". Esiste un modo per creare un indice che acceleri le query WHERE ">" o "<"?
O se ci sono altri suggerimenti sulle prestazioni di questo tipo di query, per favore fatemelo sapere.
Nota: sto usando il campo "diff_ms" come fase di denormalizzazione (equivale a time_off - time_on) che migliora le prestazioni dell'aggregazione di circa il 30% -40%.
Sto creando l'indice con questo comando:
ALTER TABLE writetest_table ADD INDEX time_on (time_on) USING BTREE;
L'esecuzione di "spiegazione" sulla query originale (con "time_on>") dice che time_on è un "possible_key" e il tipo di selezione è "SEMPLICE". La colonna "extra" dice "Utilizzo di where" e "type" è "ALL". Dopo aver aggiunto l'indice, la tabella indica che "time_on" è il tipo di chiave "MUL", che sembra corretto poiché lo stesso tempo può essere presente due volte.
Ecco lo schema della tabella:
CREATE TABLE `writetest_table` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`sessionID` int(11) DEFAULT NULL,
`time_on` timestamp NULL DEFAULT NULL,
`time_off` timestamp NULL DEFAULT NULL,
`diff_ms` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `time_on` (`time_on`)
) ENGINE=MyISAM AUTO_INCREMENT=50410902 DEFAULT CHARSET=latin1;
AGGIORNAMENTO: ho creato il seguente indice in base alla risposta di ypercube, ma ciò aumenta il tempo di interrogazione per la prima interrogazione a circa 17 secondi!
ALTER TABLE writetest_table ADD INDEX time_on__diff_ms__ix (time_on, diff_ms) ;
AGGIORNAMENTO 2: output EXPLAIN
mysql> explain select sum(diff_ms) from writetest_table where time_on > '2015-07-13 15:11:56';
+----+-------------+---------------------+-------+----------------------+----------------------+---------+------+----------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------------+-------+----------------------+----------------------+---------+------+----------+--------------------------+
| 1 | SIMPLE | writetest_table_old | index | time_on__diff_ms__ix | time_on__diff_ms__ix | 10 | NULL | 35831102 | Using where; Using index |
+----+-------------+---------------------+-------+----------------------+----------------------+---------+------+----------+--------------------------+
1 row in set (0.00 sec)
Aggiornamento 3: risultato della query richiesta
mysql> SELECT time_on FROM writetest_table ORDER BY time_on LIMIT 1;
+---------------------+
| time_on |
+---------------------+
| 2015-07-13 15:11:56 |
+---------------------+
1 row in set (0.01 sec)
SELECT COUNT(*), COUNT(diff_ms) FROM writetest_table;
writetest_table_old
" mentre la query ha from writetest_table
. È un refuso o si esegue la query in una tabella diversa?
time_on
ediff_ms
)? Cosa succede se aggiungi la queryWHERE ... AND diff_ms IS NOT NULL
?