Pregunta

Tengo una tabla muy grande (~ 100 millones de registros) en MySQL que contiene información sobre archivos. Una de las piezas de información es la fecha de modificación de cada archivo.

Necesito escribir una consulta que cuente la cantidad de archivos que se ajustan a los rangos de fechas especificados. Para hacer eso, hice una pequeña tabla que especifica estos rangos (todo en días) y se ve así:

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

Y escribió una consulta que se ve así:

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

Sin embargo, de manera bastante predecible, esta consulta tarda una eternidad en ejecutarse. Creo que es porque le estoy pidiendo a MySQL que revise la HugeFileTable 5 veces, cada vez que realice el cálculo DATEDIFF () en cada archivo.

Lo que quiero hacer en su lugar es revisar el registro HugeFileTable por registro solo una vez, y para cada archivo incremente el recuento en el total acumulado apropiado de range_name. No puedo entender cómo hacer eso ...

¿Alguien puede ayudar con esto?

Gracias.

EDITAR : Versión MySQL: 5.0.45, las tablas son MyISAM

EDIT2 : Aquí está la descripción que se solicitó en los comentarios

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   
¿Fue útil?

Solución

Primero, cree un índice en HugeFileTable.file_last_access.

Luego intente la siguiente 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;

Aquí está el EXPLAIN plan que obtuve cuando probé esta consulta en MySQL 5.0.75 (editado por brevedad):

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

Todavía no va a funcionar muy bien. Al usar GROUP BY, la consulta incurre en una tabla temporal, que puede ser costosa. No hay mucho que puedas hacer al respecto.

Pero al menos esta consulta elimina el producto cartesiano que tenía en su consulta original.


actualización: Aquí hay otra consulta que utiliza una subconsulta correlacionada pero he eliminado la <=>.

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;

El plan <=> no muestra ninguna tabla temporal o clasificación de archivos (al menos con la cantidad trivial de filas que tengo en mis tablas de prueba):

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

Pruebe esta consulta en su conjunto de datos y vea si funciona mejor.

Otros consejos

Bueno, comience asegurándose de que file_last_access sea un índice para la tabla HugeFileTable.

No estoy seguro de si esto es posible \ mejor, pero primero intente calcular los límites de fechas (archivos desde la fecha A hasta la fecha B ), luego use algunos consulta con > = y < =. Teóricamente, al menos, mejorará el rendimiento.

La comparación sería algo así como:

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

Puede obtener una pequeña mejora al eliminar CURDATE () y poner una fecha en la consulta, ya que ejecutará esta función para cada fila dos veces en su SQL.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top