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

Développement SQL Server Discussion :

Simplification requête SQL GROUPBY / MAX / MIN


Sujet :

Développement SQL Server

  1. #1
    Membre éclairé
    Homme Profil pro
    Architecte technique
    Inscrit en
    Février 2004
    Messages
    477
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Service public

    Informations forums :
    Inscription : Février 2004
    Messages : 477
    Par défaut Simplification requête SQL GROUPBY / MAX / MIN
    Bonjour à tous,

    J'ai la requête ci-dessous et j'aimerai savoir s'il est possible de l'améliorer notamment au niveau des sous requêtes qui me permettent de ramener la date associée à la valeur min (PMin) et la valeur max (PMax).
    En fait j'aimerai bien ne pas avoir à faire des sous requêtes et donc parcourir 2X ma table.

    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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
     
       WITH
          CRB_DAILY
          AS
             (SELECT compteur_id,
                     i1.[date] AS datepoint,
                     type_pt_id,
                     (sum (puissance) / 6) AS volume,
                     max (puissance) AS pmax,
                     min (puissance) AS pmin,
                     (SELECT TOP 1 datepoint
                      FROM codap.gtm_crb10mn AS a                 
                           JOIN
                           (SELECT MIN (puissance) AS PMin
                            FROM codap.gtm_crb10mn crb                             
                            WHERE     crb.compteur_id = c1.compteur_id
                                  AND crb.type_pt_id = c1.type_pt_id
                                  AND cast
                                      (dateadd (minute, -10, datepoint) AS DATE) =
                                      i1.[date] and crb.lastversion = 1
                            GROUP BY crb.compteur_id) AS b
                              ON (    a.puissance = b.PMin
                                  AND a.compteur_id = c1.compteur_id
                                  AND a.type_pt_id = c1.type_pt_id
                                  AND cast
                                      (dateadd (minute, -10, datepoint) AS DATE) =
                                      i1.[date])) AS dtmin,
                     (SELECT TOP 1 datepoint
                      FROM codap.gtm_crb10mn AS a
                           JOIN
                           (SELECT MAX (puissance) AS PMax
                            FROM codap.gtm_crb10mn crb
                            WHERE     crb.compteur_id = c1.compteur_id
                                  AND crb.type_pt_id = c1.type_pt_id
                                  AND cast
                                      (dateadd (minute, -10, datepoint) AS DATE) =
                                      i1.[date] and crb.lastversion = 1
                            GROUP BY crb.compteur_id) AS b
                              ON (    a.puissance = b.PMax
                                  AND a.compteur_id = c1.compteur_id
                                  AND a.type_pt_id = c1.type_pt_id
                                  AND cast
                                      (dateadd (minute, -10, datepoint) AS DATE) =
                                      i1.[date])) AS dtmax,
                     count (*) AS iCount
              FROM codap.gtm_crb10mn c1
                   INNER JOIN codap.gtm_interval_10mn i1
                      ON i1.datepoint = c1.datepoint
              WHERE c1.lastversion = 1
              GROUP BY compteur_id, type_pt_id, i1.[date])
       SELECT compteur_id,
              datepoint,
              type_pt_id,
              volume,
              pmax,
              pmin,
              dtmin,
              dtmax,
              iCount
       FROM CRB_DAILY

  2. #2
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 999
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 999
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par Pfeffer Voir le message
    Bonjour à tous,

    J'ai la requête ci-dessous et j'aimerai savoir s'il est possible de l'améliorer notamment au niveau des sous requêtes qui me permettent de ramener la date associée à la valeur min (PMin) et la valeur max (PMax).
    En fait j'aimerai bien ne pas avoir à faire des sous requêtes et donc parcourir 2X ma table.
    Avez vous regardé le plan de requête avant d'affirmer que SQL Server parcoure deux fois la tables ?
    1) s'il y a un index adéquat il n'y a pas de parcours de table mais une recherche d'index
    2) SQL Server factorise ce qu'il est possible de factoriser, ici les 2 sous requêtes devraient être fusionnée en une seule...

    En revanche votre requête contient beaucoup de choses qui la rende potentiellement contre-performante :
    1) dans le prédicat suivant :
    cast(dateadd (minute, -10, datepoint) AS DATE) = i1.[date]
    si ce sont des colonnes de type DATE, alors le CAST est inutile...

    2) vous faites des jointures triangulaire dans vos sous requêtes... Dès lors aucun index n'est utilisable.... Il est probablement possible d'éviter cela.
    Expliquez nous ce que vous voulez faire, Donnez nous un jeu d'essai et le DDL des tables en jeu.

    Mise en forme plus lisible :

    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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    WITH
    CRB_DAILY AS
    (
    SELECT compteur_id,
           i1.[date] AS datepoint,
           type_pt_id,
           (sum (puissance) / 6) AS volume,
           max (puissance) AS pmax,
           min (puissance) AS pmin,
           (SELECT TOP 1 datepoint
            FROM   codap.gtm_crb10mn AS a                 
                   JOIN (SELECT MIN (puissance) AS PMin
                         FROM   codap.gtm_crb10mn crb                             
                         WHERE  crb.compteur_id = c1.compteur_id
                           AND  crb.type_pt_id = c1.type_pt_id
                           AND  cast(dateadd (minute, -10, datepoint) AS DATE) = i1.[date] 
                           AND  crb.lastversion = 1
                         GROUP  BY crb.compteur_id) AS b
                      ON a.puissance = b.PMin
                         AND a.compteur_id = c1.compteur_id
                         AND a.type_pt_id = c1.type_pt_id
                         AND cast(dateadd (minute, -10, datepoint) AS DATE) = i1.[date]) AS dtmin,
           (SELECT TOP 1 datepoint
            FROM   codap.gtm_crb10mn AS a
                   JOIN (SELECT MAX(puissance) AS PMax
                         FROM   codap.gtm_crb10mn crb
                         WHERE  crb.compteur_id = c1.compteur_id
                           AND  crb.type_pt_id = c1.type_pt_id
                           AND  CAST(DATEADD(minute, -10, datepoint) AS DATE) = i1.[date]
                           AND  crb.lastversion = 1
                         GROUP BY crb.compteur_id) AS b
                      ON a.puissance = b.PMax
                         AND a.compteur_id = c1.compteur_id
                         AND a.type_pt_id = c1.type_pt_id
                         AND cast(dateadd (minute, -10, datepoint) AS DATE) = i1.[date]) AS dtmax,
                     count (*) AS iCount
    FROM   codap.gtm_crb10mn c1
           INNER JOIN codap.gtm_interval_10mn i1
              ON i1.datepoint = c1.datepoint
    WHERE  c1.lastversion = 1
    GROUP  BY compteur_id, type_pt_id, i1.[date]
    )
    SELECT compteur_id,
           datepoint,
           type_pt_id,
           volume,
           pmax,
           pmin,
           dtmin,
           dtmax,
           iCount
    FROM   CRB_DAILY;
    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  3. #3
    Membre éclairé
    Homme Profil pro
    Architecte technique
    Inscrit en
    Février 2004
    Messages
    477
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Service public

    Informations forums :
    Inscription : Février 2004
    Messages : 477
    Par défaut
    Alors j'ai regardé le plan de maintenance et SQL m'a proposé de créer un index complémentaire.
    Ca marche déja un peu mieux ...

    Les CAST sont pour moi obligatoires je pense.
    D'un côté j'ai un datetime (dd/mm/yyyy hh:mm) et de l'autre une date, l'idée étant de trouver le DATETIME auquel est associé le MIN(PUISSANCE) ou le MAX(puissance) sur une journée particulière ou il y a plusieurs enregistrements.

    Comment améliorer mes jointures triangulaires dans ce cas ?

  4. #4
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 999
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 999
    Billets dans le blog
    6
    Par défaut
    Donnez le code du CREATE des tables.....

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  5. #5
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 953
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 953
    Par défaut
    Je ne pense pas que first et last existe en version agrégée sur sql server.

    Je partirais donc sur du first_value avant de faire l'agrégation, quelque chose comme (requête non testée) :

    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
    18
    19
    20
    21
    22
    23
      with crb_daily as (
    select compteur_id
         , i1.[date] as datepoint
         , type_pt_id
         , first_value(c1.datepoint) over (partition by c1.compteur_id, c1.type_pt_id, cast(dateadd (minute, -10, c1.datepoint) as date) order by c1.puissance asc)  as dtmin
         , first_value(c1.datepoint) over (partition by c1.compteur_id, c1.type_pt_id, cast(dateadd (minute, -10, c1.datepoint) as date) order by c1.puissance desc) as dtmax
      from codap.gtm_crb10mn c1
      join codap.gtm_interval_10mn i1
        on i1.datepoint = c1.datepoint
     where c1.lastversion = 1
     group by compteur_id, type_pt_id, i1.[date]
    )
    select compteur_id
         , datepoint
         , type_pt_id
         , (sum (puissance) / 6) as volume
         , max (puissance) as pmax
         , min (puissance) as pmin
         , dtmin
         , dtmax
         , count (*) as iCount
      from crb_daily
     group by compteur_id, datepoint, type_pt_id, dtmin, dtmax;

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

Discussions similaires

  1. [AC-97] Requte SQL et MAX(date)
    Par m.semal dans le forum Requêtes et SQL.
    Réponses: 4
    Dernier message: 14/07/2013, 09h57
  2. Requête SQL Fonction Max(LaDate)
    Par ElVatoLoco69 dans le forum Requêtes
    Réponses: 3
    Dernier message: 20/02/2012, 11h55
  3. Requête SQL avec max
    Par Guinoumi dans le forum Langage SQL
    Réponses: 2
    Dernier message: 22/07/2010, 14h08
  4. Simplification requête SQL
    Par squall6969 dans le forum Requêtes
    Réponses: 1
    Dernier message: 31/07/2008, 13h55
  5. Requête SQL pour max entre 3 colonnes
    Par lucho013 dans le forum Requêtes et SQL.
    Réponses: 8
    Dernier message: 10/10/2007, 17h06

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