Je travaille sur un schéma pour un système d'analyse qui suit les temps d'utilisation, et il est nécessaire de voir le temps d'utilisation total dans une certaine plage de dates.
Pour donner un exemple simple, ce type de requête serait exécuté souvent:
select sum(diff_ms) from writetest_table where time_on > ("2015-07-13 15:11:56");
Cette requête prend généralement environ 7 secondes sur une table fortement peuplée. Il compte environ 35 millions de lignes, MyISAM sur MySQL fonctionnant sur Amazon RDS (db.m3.xlarge).
La suppression de la clause WHERE fait que la requête ne prend que 4 secondes et l'ajout d'une seconde clause (time_off> XXX) ajoute 1,5 seconde supplémentaire, ce qui porte le temps de requête à 8,5 secondes.
Comme je sais que ces types de requêtes seront généralement effectués, je voudrais optimiser les choses afin qu'elles soient plus rapides, idéalement en dessous de 5 secondes.
J'ai commencé par ajouter un index sur time_on, et bien que cela ait considérablement accéléré une requête WHERE "=", cela n'a eu aucun effet sur la requête ">". Existe-t-il un moyen de créer un index qui accélérerait les requêtes WHERE ">" ou "<"?
Ou s'il y a d'autres suggestions sur les performances de ce type de requête, faites-le moi savoir.
Remarque: J'utilise le champ "diff_ms" comme étape de dénormalisation (il est égal à time_off - time_on) qui améliore les performances de l'agrégation d'environ 30% -40%.
Je crée l'index avec cette commande:
ALTER TABLE writetest_table ADD INDEX time_on (time_on) USING BTREE;
Exécuter "expliquer" sur la requête d'origine (avec "time_on>") indique que time_on est une "possible_key" et le select_type est "SIMPLE". La colonne "extra" indique "Utiliser où" et "type" est "TOUT". Après l'ajout de l'index, le tableau indique que "time_on" est de type "MUL", ce qui semble correct car le même temps peut être présent deux fois.
Voici le schéma de la table:
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;
MISE À JOUR: J'ai créé l'index suivant basé sur la réponse de ypercube, mais cela augmente le temps de requête pour la première requête à environ 17 secondes!
ALTER TABLE writetest_table ADD INDEX time_on__diff_ms__ix (time_on, diff_ms) ;
MISE À JOUR 2: sortie 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)
Mise à jour 3: résultat de la requête demandée
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
" pendant la requête from writetest_table
. Est-ce une faute de frappe ou vous exécutez la requête dans une table différente?
time_on
etdiff_ms
)? Que se passe-t-il si vous ajoutez une requêteWHERE ... AND diff_ms IS NOT NULL
?