Domanda

Ho una tabella molto grande (~ 100 milioni di record) in MySQL che contiene informazioni sui file. Una delle informazioni è la data modificata di ciascun file.

Devo scrivere una query che conterà il numero di file che rientrano negli intervalli di date specificati. Per fare ciò ho creato una piccola tabella che specifica questi intervalli (tutti in giorni) e si presenta così:

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 ha scritto una query simile a questa:

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

Tuttavia, abbastanza prevedibilmente, l'esecuzione di questa query richiede un'eternità. Penso che sia perché sto chiedendo a MySQL di passare attraverso la HugeFileTable 5 volte, ogni volta che eseguo il calcolo DATEDIFF () su ciascun file.

Quello che voglio fare invece è passare attraverso il record HugeFileTable per record solo una volta, e per ogni file incrementare il conteggio nel totale corrente range_name appropriato. Non riesco a capire come farlo ....

Qualcuno può dare una mano con questo?

Grazie.

EDIT : versione MySQL: 5.0.45, le tabelle sono MyISAM

EDIT2 : ecco la descrizione richiesta nei commenti

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   
È stato utile?

Soluzione

Innanzitutto, crea un indice su HugeFileTable.file_last_access.

Quindi prova la seguente query:

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;

Ecco il EXPLAIN piano che ho ottenuto quando ho provato questa query su MySQL 5.0.75 (modificato per brevità):

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

Non funzionerà ancora molto bene. Utilizzando GROUP BY, la query comporta una tabella temporanea, che può essere costosa. Non puoi fare molto al riguardo.

Ma almeno questa query elimina il prodotto cartesiano che avevi nella tua query originale.


aggiornamento: Ecco un'altra query che utilizza una sottoquery correlata ma ho eliminato il <=>.

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;

Il piano <=> non mostra alcuna tabella temporanea o fileort (almeno con la quantità banale di righe che ho nelle mie tabelle di test):

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

Prova questa query sul tuo set di dati e verifica se funziona meglio.

Altri suggerimenti

Bene, inizia assicurandoti che file_last_access sia un indice per la tabella HugeFileTable.

Non sono sicuro che sia possibile \ meglio, ma prova prima a calcolare i limiti di date (file dalla data A alla data B ), quindi usa alcuni interroga con > = e < =. Almeno teoricamente migliorerà le prestazioni.

Il confronto sarebbe qualcosa del tipo:

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

Puoi ottenere un piccolo miglioramento rimuovendo CURDATE () e inserendo una data nella query poiché eseguirà questa funzione per ogni riga due volte nel tuo SQL.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top