Estou trabalhando em um esquema para um sistema de análise que rastreia os tempos de uso e é necessário ver o tempo total de uso em um determinado período.
Para dar um exemplo simples, esse tipo de consulta seria executado com frequência:
select sum(diff_ms) from writetest_table where time_on > ("2015-07-13 15:11:56");
Essa consulta normalmente leva cerca de 7 segundos em uma tabela que é muito preenchida. Possui ~ 35 milhões de linhas, o MyISAM no MySQL é executado no Amazon RDS (db.m3.xlarge).
A eliminação da cláusula WHERE faz com que a consulta demore apenas 4 segundos e a adição de uma segunda cláusula (time_off> XXX) adiciona mais 1,5 segundos, elevando o tempo da consulta para 8,5 segundos.
Como eu sei que esses tipos de consultas serão normalmente feitos, eu gostaria de otimizar as coisas para que sejam mais rápidas, de preferência abaixo de 5 segundos.
Comecei adicionando um índice em time_on e, apesar de acelerar drasticamente uma consulta WHERE "=", ela não teve efeito na consulta ">". Existe uma maneira de criar um índice que acelere as consultas WHERE ">" ou "<"?
Ou, se houver outras sugestões sobre o desempenho desse tipo de consulta, entre em contato.
Nota: Estou usando o campo "diff_ms" como uma etapa de desnormalização (igual a time_off - time_on) que melhora o desempenho da agregação em cerca de 30% a 40%.
Estou criando o índice com este comando:
ALTER TABLE writetest_table ADD INDEX time_on (time_on) USING BTREE;
A execução de "explicação" na consulta original (com "time_on>") indica que time_on é uma "chave possível" e o tipo de seleção é "SIMPLES". A coluna "extra" diz "Usando onde" e "tipo" é "TUDO". Depois que o índice foi adicionado, a tabela diz que "time_on" é o tipo de chave "MUL", que parece correto, pois o mesmo tempo pode estar presente duas vezes.
Aqui está o esquema da tabela:
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;
UPDATE: Criei o seguinte índice com base na resposta do ypercube, mas isso aumenta o tempo de consulta da primeira consulta para cerca de 17 segundos!
ALTER TABLE writetest_table ADD INDEX time_on__diff_ms__ix (time_on, diff_ms) ;
ATUALIZAÇÃO 2: saída 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)
Atualização 3: resultado da 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
" enquanto a consulta o possui from writetest_table
. Isso é um erro de digitação ou você executa a consulta em uma tabela diferente?
time_on
ediff_ms
)? O que acontece se você adicionar na consultaWHERE ... AND diff_ms IS NOT NULL
?