Estoy trabajando en un esquema para un sistema de análisis que rastrea los tiempos de uso, y es necesario ver el tiempo de uso total en un cierto rango de fechas.
Para dar un ejemplo simple, este tipo de consulta se ejecutará con frecuencia:
select sum(diff_ms) from writetest_table where time_on > ("2015-07-13 15:11:56");
Esta consulta generalmente toma alrededor de 7 segundos en una tabla que está muy poblada. Tiene ~ 35 millones de filas, MyISAM en MySQL ejecutándose en Amazon RDS (db.m3.xlarge).
Deshacerse de la cláusula WHERE hace que la consulta tome solo 4 segundos, y agregar una segunda cláusula (time_off> XXX) agrega 1.5 segundos adicionales, lo que lleva el tiempo de consulta a 8.5 segundos.
Como sé que este tipo de consultas se realizarán comúnmente, me gustaría optimizar las cosas para que sean más rápidas, idealmente por debajo de 5 segundos.
Comencé agregando un índice en time_on, y aunque eso aceleró drásticamente una consulta WHERE "=", no tuvo ningún efecto en la consulta ">". ¿Hay alguna manera de crear un índice que acelere las consultas WHERE ">" o "<"?
O si hay alguna otra sugerencia sobre el rendimiento de este tipo de consulta, hágamelo saber.
Nota: Estoy usando el campo "diff_ms" como un paso de desnormalización (es igual a time_off - time_on) que mejora el rendimiento de la agregación en un 30% -40%.
Estoy creando el índice con este comando:
ALTER TABLE writetest_table ADD INDEX time_on (time_on) USING BTREE;
Ejecutar "explicar" en la consulta original (con "time_on>") dice que time_on es una "posible_clave" y select_type es "SIMPLE". La columna "extra" dice "Uso de where" y "type" es "ALL". Después de agregar el índice, la tabla dice que "time_on" es el tipo de clave "MUL", lo que parece correcto ya que el mismo tiempo puede estar presente dos veces.
Aquí está el esquema de la tabla:
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;
ACTUALIZACIÓN: ¡Creé el siguiente índice basado en la respuesta de ypercube, pero esto aumenta el tiempo de consulta para la primera consulta a alrededor de 17 segundos!
ALTER TABLE writetest_table ADD INDEX time_on__diff_ms__ix (time_on, diff_ms) ;
ACTUALIZACIÓN 2: EXPLICAR la salida
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)
Actualización 3: resultado de la consulta solicitada
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
" mientras que la consulta tiene from writetest_table
. ¿Es un error tipográfico o ejecuta la consulta en una tabla diferente?
time_on
ydiff_ms
)? ¿Qué sucede si agrega la consultaWHERE ... AND diff_ms IS NOT NULL
?