IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Requêtes MySQL Discussion :

Calcul de consommation [MySQL-5.0]


Sujet :

Requêtes MySQL

  1. #1
    Candidat au Club
    Homme Profil pro
    Directeur des systèmes d'information
    Inscrit en
    Juillet 2014
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur des systèmes d'information
    Secteur : Santé

    Informations forums :
    Inscription : Juillet 2014
    Messages : 4
    Points : 3
    Points
    3
    Par défaut Calcul de consommation
    Bonjour à tous

    A partir de relevé journalier de compteur d'imprimantes effectué par des requetes SNMP, je constitue une base de données
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    CREATE TABLE `test` (
      `Last check` datetime NOT NULL,
      `Mac Address` varchar(17) NOT NULL,
      `Engine count` mediumint(9) default NULL,
      PRIMARY KEY  (`Last check`,`Mac Address`),
      KEY `Last check` (`Last check`),
      KEY `Mac Address` (`Mac Address`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    `Last check` est la date et l'heure de la requete SNMP, `Mac Address` l'adresse Mac de l'imprimante et `Engine count` le compteur de pages imprimées
    je cherche à établir une consommation journalière, par différence des compteurs N à N-1, pour une même adresse Mac
    J'ai établi une requete qui me permet de sortir ce résultat :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    SELECT o.`Mac Address` , o.`Last check` , o.`Engine count` - po.`Engine count` 
    FROM test o
    LEFT JOIN test po ON ( o.`Mac Address` = po.`Mac Address` ) 
    WHERE po.`Last check` 
    IN (
     
    SELECT MAX( tmp.`Last check` ) 
    FROM test tmp use index (`Last check`,`Mac Address`)
    WHERE tmp.`Last check` < o.`Last check` 
    AND tmp.`Mac Address` = o.`Mac Address` 
    )
    ORDER BY `o`.`Mac Address` ASC  
    limit 30;

    J'ai cependant un gros problème de performance. En effet, avec environ 3000 lignes dans la table, la requete dure 15s. avec 65 000 lignes dans la table, la requete dure plusieurs heures.
    pour exemple, j'ai limité à 30 résultats, avec un EXPLAIN


    30 lignes (0.475 s)

    id? select_type? table? type? possible_keys? key? key_len? ref? rows? Extra?
    1 PRIMARY o index Mac Address Mac Address 53 NULL 68237
    1 PRIMARY po ref Mac Address Mac Address 53 imprimantes.o.Mac Address 38 Using where
    2 DEPENDENT SUBQUERY tmp ref Last check,Mac Address Mac Address 53 imprimantes.o.Mac Address 35 Using where; Using index
    Qui peut m'aider à optimise ma requete et/ou ma table ?
    Ou une autre méthode ?

    Encore à tous pour votre aide

    Patrice

  2. #2
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Bonjour,

    qu'est ce que donne votre requete si vous inversez l'ordre des colonne de la clef primaire (ou que vous créez un index (`Mac Address`, `Last check`) et que vous supprimez votre USE INDEX) ?

  3. #3
    Candidat au Club
    Homme Profil pro
    Directeur des systèmes d'information
    Inscrit en
    Juillet 2014
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur des systèmes d'information
    Secteur : Santé

    Informations forums :
    Inscription : Juillet 2014
    Messages : 4
    Points : 3
    Points
    3
    Par défaut Suite
    Merci
    Quand j'enleve le "USE INDEX", la transaction s'execute en 1,294s
    Je suis à 1,075s en inversant les champs et 0,675s par création d'un index avec les 2 champs à la place de la clef primaire

  4. #4
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Il faudra en effet un index adéquat pour supporter la requête. Donc soit inverser l'ordre des colonnes de la clef primaire si cela n'impacte pas d'autres requêtes, soit créer un nouvel index, en incluant la colonne `Engine count` pour qu'il soit couvrant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    CREATE UNIQUE INDEX IX_test ON test(`Mac Address`, `Last check` , `Engine count`)
    Vous pouvez aussi essayer cette requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT  a.`Mac Address`, MAX(b.`Last check`), MAX(b.`Engine count`) - a.`Engine count`
    FROM test a
    INNER JOIN test b
        ON b.`Mac Address` = a.`Mac Address`
    	AND b.`Last check` > a.`Last check`
    GROUP BY a.`Mac Address`, a.`Last check`
    HAVING COUNT(*) = 1
    Attention, les imprimantes n'ayant qu'une seule ligne ne ressortiront pas. Si cela est gênant, il faudrait les ajouter spécifiquement avec un UNION ALL qui aura un cout non négligeable :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    SELECT  a.`Mac Address`, MAX(b.`Last check`), MAX(b.`Engine count`) - a.`Engine count`
    FROM test a
    INNER JOIN test b
        ON b.`Mac Address` = a.`Mac Address`
    	AND b.`Last check` > a.`Last check`
    GROUP BY a.`Mac Address`, a.`Last check`
    HAVING COUNT(*) = 1
    UNION ALL 
    SELECT a.`Mac Address`, a.`Last check`, 0
    FROM test a
    WHERE not exists(
    	SELECT 1
    	FROM test b
    	WHERE b.`Mac Address` = a.`Mac Address`
    	AND b.`Last check`> a.`Last check`
    )

  5. #5
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    ou une alternative peut-être moins couteuse pour prendre en compte les imprimantes avec une seule ligne, mais qui suppose que le compteur s'incrémente ou ne change pas (le résultat serait faux dans le cas d'une "consommation négative", mais dans votre cas, ça ne semble pas possible)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    SELECT `Mac Address`, `Last check`,  MAX(conso)
    FROM (
    SELECT  a.`Mac Address`, MAX(b.`Last check`) AS `Last check`, MAX(b.`Engine count`) - a.`Engine count` as Conso
    FROM test a
    INNER JOIN test b
        ON b.`Mac Address` = a.`Mac Address`
    	AND b.`Last check` >= a.`Last check`
    GROUP BY a.`Mac Address`, a.`Last check`
    HAVING COUNT(*) < 3) AS T
    GROUP BY `Mac Address`, `Last check`

  6. #6
    Candidat au Club
    Homme Profil pro
    Directeur des systèmes d'information
    Inscrit en
    Juillet 2014
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur des systèmes d'information
    Secteur : Santé

    Informations forums :
    Inscription : Juillet 2014
    Messages : 4
    Points : 3
    Points
    3
    Par défaut Suite
    Merci
    Effectivement, les requetes s'executent mais ne ramene pas le bon résultat
    je souhaite comparer les compteurs N et N-1 établis lors des scans J et J-1
    par exemple, si j'avais 3 jours de scan avec 2 imprimantes détectées, j'aurais dans le fichier initial (table Test) 3x2=6 enregistrements
    la requete qui me compare devrait me ramener 4 enregistrements (soit le nombre d'imprimantes x le nb de jours de scan-1)
    Hors la requete proposée me ramene uniquement une ligne par imprimante

  7. #7
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Ah, j'avais mal compris, je pensais que vous ne vouliez que le dernier écart.

    Donc :

    Toujours si l'on suppose que la quantité est forcément stable ou criossante, vous pouvez faire comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    SELECT a.`Mac Address`, a.`Last check`, a.`Engine count` - MAX(b.`Engine count`)
    FROM test a
    LEFT JOIN test b
    	ON b.`Mac Address` = a.`Mac Address`
    	AND b.`Last check` < a.`Last check`	
    GROUP BY a.`Mac Address`, a.`Last check`, a.`Engine count`

    Idéalement, il aurait fallu traiter ce problème avec des fonctions analytiques, mais celles-ci ne sont pas disponible sous MySQL.
    Voici donc une alternative moins académique, mais qui peut donner de bons résultat :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    SELECT  
    	a.`Mac Address`, 
    	a.`Last check`, 
    	a.`Engine count` - (
    		SELECT `Engine count` 
    		FROM test b 
    		WHERE b.`Mac Address` = a.`Mac Address`
    		AND b.`Last check` < a.`Last check`
    		ORDER BY `Last check` DESC
    		LIMIT 1
    )
    FROM test a

  8. #8
    Candidat au Club
    Homme Profil pro
    Directeur des systèmes d'information
    Inscrit en
    Juillet 2014
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur des systèmes d'information
    Secteur : Santé

    Informations forums :
    Inscription : Juillet 2014
    Messages : 4
    Points : 3
    Points
    3
    Par défaut Suite et fin
    je m'incline et je dis :"chapeau" !
    Cela fonctionne
    Encore merci

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [AC-2003] Calcul de consommation journalière
    Par cvfe13 dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 04/02/2012, 17h37
  2. Calcul de consommation, comparer deux lignes
    Par ZoummuoZ dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 27/08/2010, 09h25
  3. Réponses: 0
    Dernier message: 29/06/2009, 11h33
  4. [MySQL] Calcul du total des ventes et des consommations
    Par dubitoph dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 19/10/2007, 17h16
  5. Calculer la mémorie consommé par JAVA
    Par aikinhdo dans le forum Langage
    Réponses: 9
    Dernier message: 09/10/2007, 12h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo