2010-08-06 7 views
3

Désolé, le titre de la question est un peu vague, alors voici un exemple pratique.Comment regrouper, placer et filtrer un ensemble de résultats pour un ensemble de données très volumineux

J'ai une table dans laquelle chaque utilisateur (userid) obtient une valeur tous les quelques jours. Je veux trouver la dernière de ces valeurs pour chaque utilisateur, ventilée par mois, et compter leur nombre dans une fourchette.

Voici un exemple de tableau et des données représentatives:

CREATE TABLE `datasource` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , 
    `userId` INT UNSIGNED NOT NULL , 
    `unixts` INT UNSIGNED NOT NULL , 
    `value` INT UNSIGNED NOT NULL , 
    INDEX (`userId`) 
); 

INSERT INTO `datasource` 
    (`userId`, `unixts`, `value`) 
VALUES 
    (1, UNIX_TIMESTAMP('2010-07-01'), 500), 
    (1, UNIX_TIMESTAMP('2010-07-15'), 610), 
    (1, UNIX_TIMESTAMP('2010-08-02'), 740), 

    (2, UNIX_TIMESTAMP('2010-07-03'), 506), 
    (2, UNIX_TIMESTAMP('2010-07-18'), 640), 
    (2, UNIX_TIMESTAMP('2010-08-09'), 340), 

    (3, UNIX_TIMESTAMP('2010-07-03'), 506), 
    (3, UNIX_TIMESTAMP('2010-08-18'), 640) 
; 

Maintenant, voici une requête pour obtenir ce que je suis après:

select 
    month(FROM_UNIXTIME(unixts)) as month, 
    sum(if(value >= 700, 1, 0)) as '700 and up', 
    sum(if(value BETWEEN 600 AND 699, 1, 0)) as '600-699', 
    sum(if(value BETWEEN 500 AND 599, 1, 0)) as '500-599', 
    sum(if(value <= 499, 1, 0)) as '499 and below', 
    count(*) as total 
from 
    datasource 
where 
    id in (
     select 
      max(id) 
     from 
      datasource 
     where 
      unixts between UNIX_TIMESTAMP('2010-07-01') and UNIX_TIMESTAMP('2010-09-01') 
     group by 
      userId, month(from_unixtime(unixts)) 
    ) 
group by 
    month(FROM_UNIXTIME(unixts)); 

+-------+------------+---------+---------+---------------+-------+ 
| month | 700 and up | 600-699 | 500-599 | 499 and below | total | 
+-------+------------+---------+---------+---------------+-------+ 
|  7 |   0 |  2 |  1 |    0 |  3 | 
|  8 |   1 |  1 |  0 |    1 |  3 | 
+-------+------------+---------+---------+---------------+-------+ 

Cette requête fonctionne très bien pour notre petit jeu de résultats. Toutefois, si vous lancez 44 millions de lignes dans la table de sources de données, il s'interrompt.

Existe-t-il un moyen optimisé pour écrire cette requête qui peut accomplir ce que je veux sans arrimer mysql pendant plusieurs jours?

Répondre

0

Créez un index dans la colonne de valeur.

create index value_index ON datasource(value) 

Vous ne devriez avoir à faire qu'une seule fois. Cela ralentira légèrement vos inserts.

2

Essayez EXPLAIN sélectionnez ...;

Cela vous indiquera le fonctionnement de la requête. Vous pouvez alors voir si une analyse de table complète a lieu pour une raison quelconque et prendre des mesures pour la corriger. Cela inclurait probablement la suggestion de Cfreak. Vous pouvez également afficher les résultats ici et nous verrons ce que nous pouvons faire.

Questions connexes