Pergunta

Eu tenho uma tabela muito grande (~ 100MilhõesRMB Records) no MySQL que contém informações sobre arquivos. Uma das peças de informação é a data de modificação de cada arquivo.

Eu preciso escrever uma consulta que irá contar o número de arquivos que se encaixam em intervalos de datas especificadas. Para fazer isso eu fiz uma pequena mesa que especifica esses intervalos (todos em dias) e se parece com isto:

DateRanges
range_id   range_name   range_start   range_end
1          0-90         0             90
2          91-180       91            180
3          181-365      181           365
4          366-1095     366           1095
5          1096+        1096          999999999

E escreveu uma consulta parecida com esta:

SELECT r.range_name, sum(IF((DATEDIFF(CURDATE(),t.file_last_access) > r.range_start and DATEDIFF(CURDATE(),t.file_last_access) < r.range_end),1,0)) as FileCount
FROM `DateRanges` r, `HugeFileTable` t
GROUP BY r.range_name

No entanto, muito previsivelmente, esta consulta leva uma eternidade para ser executado. Eu acho que é porque eu estou pedindo MySQL para percorrer as HugeFileTable 5 vezes, cada vez que executar o cálculo DATEDIFF () em cada arquivo.

O que eu quero fazer é em vez de ir através do registro HugeFileTable pelo registro apenas uma vez, e para cada arquivo incrementar a contagem no RANGE_NAME correndo totais apropriado. Eu não consigo descobrir como fazer isso ....

Alguém pode ajudar com isso?

Graças.

Editar : MySQL Versão: 5.0.45, tabelas são MyISAM

EDIT2 : Aqui está a descibe que foi solicitado nos comentários

id  select_type  table  type  possible_keys  key  key_len  ref  rows      Extra  
1   SIMPLE       r      ALL   NULL           NULL NULL     NULL 5         Using temporary; Using filesort 
1   SIMPLE       t      ALL   NULL           NULL NULL     NULL 96506321   
Foi útil?

Solução

Em primeiro lugar, criar um índice em HugeFileTable.file_last_access.

Em seguida, tente a seguinte consulta:

SELECT r.range_name, COUNT(t.file_last_access) as FileCount
FROM `DateRanges` r
 JOIN `HugeFileTable` t 
 ON (t.file_last_access BETWEEN 
   CURDATE() + INTERVAL r.range_start DAY AND 
   CURDATE() + INTERVAL r.range_end DAY)
GROUP BY r.range_name;

Aqui está o plano EXPLAIN que eu tenho quando eu tentei esta pergunta em MySQL 5.0.75 (editada por brevidade):

+-------+-------+------------------+----------------------------------------------+
| table | type  | key              | Extra                                        |
+-------+-------+------------------+----------------------------------------------+
| t     | index | file_last_access | Using index; Using temporary; Using filesort | 
| r     | ALL   | NULL             | Using where                                  | 
+-------+-------+------------------+----------------------------------------------+

É ainda não vai funcionar muito bem. Usando GROUP BY, a consulta incorre em uma tabela temporária, que pode ser caro. Não há muito que possamos fazer sobre isso.

Mas pelo menos essa consulta elimina o produto cartesiano que você tinha em sua consulta original.


atualização:. Aqui está outra consulta que utiliza uma subconsulta correlacionada, mas eu ter eliminado o GROUP BY

SELECT r.range_name,
  (SELECT COUNT(*) 
   FROM `HugeFileTable` t 
   WHERE t.file_last_access BETWEEN 
     CURDATE() - INTERVAL r.range_end DAY AND 
     CURDATE() - INTERVAL r.range_start DAY
  ) as FileCount
FROM `DateRanges` r;

O EXPLAIN plano mostra a tabela não temporário ou filesort (pelo menos com a quantidade trivial de linhas que eu tenho em minhas tabelas de teste):

+----+--------------------+-------+-------+------------------+--------------------------+
| id | select_type        | table | type  | key              | Extra                    |
+----+--------------------+-------+-------+------------------+--------------------------+
|  1 | PRIMARY            | r     | ALL   | NULL             |                          | 
|  2 | DEPENDENT SUBQUERY | t     | index | file_last_access | Using where; Using index | 
+----+--------------------+-------+-------+------------------+--------------------------+

Tente esta pergunta em seu conjunto de dados e ver se ele tem um desempenho melhor.

Outras dicas

Bem, começar por ter certeza que file_last_access é um index para o HugeFileTable mesa.

Eu não tenho certeza se isso é possível \ melhor, mas tentar calcular os limites datas primeiro (arquivos a partir da data A para data B ), então usar algum consulta com> = e <=. Será, pelo menos teoricamente, melhorar o desempenho.

A comparação seria algo como:

 t.file_last_access >= StartDate AND t.file_last_access <= EndDate 

Você pode obter uma pequena melhora, removendo CURDATE () e colocar uma data na consulta uma vez que irá executar essa função para cada linha duas vezes em seu SQL.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top