Tentei resolver o seguinte problema por cerca de uma hora agora e ainda não consegui avançar mais.
Ok, eu tenho uma tabela (MyISAM):
+---------+-------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| http | smallint(3) | YES | MUL | 200 | |
| elapsed | float(6,3) | NO | | NULL | |
| cached | tinyint(1) | YES | | NULL | |
| ip | int(11) | NO | | NULL | |
| date | timestamp | NO | MUL | CURRENT_TIMESTAMP | |
+---------+-------------+------+-----+-------------------+----------------+
Por favor, não se importe com os índices, estou brincando tentando encontrar uma solução. Agora, aqui está a minha consulta.
SELECT http,
COUNT( http ) AS count
FROM reqs
WHERE DATE(date) >= cast(date_sub(date(NOW()),interval 24 hour) as datetime)
GROUP BY http
ORDER BY count;
a tabela está armazenando informações sobre solicitações da web recebidas, portanto é um banco de dados bastante grande.
+-----------+
| count(id) |
+-----------+
| 782412 |
+-----------+
observe que não há melhor maneira de definir uma chave primária, pois a coluna id será o único identificador exclusivo que tenho. A consulta acima mencionada leva cerca de 0,6-1,6 segundos para executar.
Qual índice seria inteligente? Imaginei que a data de indexação me daria cardinalidade "ruim" e, portanto, o MySQL não a usaria. http também é uma má escolha, pois existem apenas cerca de 20 valores possíveis.
Obrigado pela ajuda!
Atualização 1 Adicionei um índice em (http, data) conforme sugerido pelo ypercube:
mysql> CREATE INDEX httpDate ON reqs (http, date);
e usou sua consulta, mas teve um desempenho igualmente ruim. O índice adicionado:
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| reqs | 0 | PRIMARY | 1 | id | A | 798869 | NULL | NULL | | BTREE | |
| reqs | 1 | httpDate | 1 | http | A | 19 | NULL | NULL | YES | BTREE | |
| reqs | 1 | httpDate | 2 | date | A | 99858 | NULL | NULL | | BTREE | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
e o EXPLAIN
+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+
| 1 | PRIMARY | r | range | NULL | httpDate | 3 | NULL | 20 | Using index for group-by; Using temporary; Using filesort |
| 2 | DEPENDENT SUBQUERY | ri | ref | httpDate | httpDate | 3 | func | 41768 | Using where; Using index |
+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+
Versão do servidor MySQL:
mysql> SHOW VARIABLES LIKE "%version%";
+-------------------------+---------------------+
| Variable_name | Value |
+-------------------------+---------------------+
| protocol_version | 10 |
| version | 5.1.73 |
| version_comment | Source distribution |
| version_compile_machine | x86_64 |
| version_compile_os | redhat-linux-gnu |
+-------------------------+---------------------+
5 rows in set (0.00 sec)
fonte
http
coluna ser anulável. Investigarei amanhã, se encontrar tempo.http NOT NULL
) e copiando todos os dados para ela (exceto as linhas com http NULL, é claro.)Respostas:
Eu tenho três sugestões
SUGESTÃO # 1: reescreva a consulta
Você deve reescrever a consulta da seguinte maneira
ou
O WHERE não deve ter uma função nos dois lados do sinal de igual. A data no lado esquerdo do sinal de igual facilita o uso do Query Optimizer por um índice.
SUGESTÃO # 2: Índice de Suporte
Eu também sugeriria um índice diferente
Eu sugiro essa ordem de colunas porque o
date
entradas seriam contíguas no índice. Em seguida, a consulta simplesmente coletahttp
valores sem ignorar as lacunashttp
.SUGESTÃO # 3: Buffer de chave maior (opcional)
O MyISAM usa apenas o cache de índice. Como a consulta não deve tocar no
.MYD
arquivo, você deve usar um buffer de chave MyISAM um pouco maior.Para configurá-lo para 256M
Em seguida, defina-o
my.cnf
Não é necessário reiniciar o MySQL
De uma chance !!!
fonte
Altere seu tipo de coluna de data para um número inteiro. Armazene a data como uma data Unix em número inteiro. O registro de data e hora é muito maior que um int. Você conseguiria um pouco disso.
fonte
INT
eTIMESTAMP
precisam de 4 bytes.