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 :

Problème sous-requête complexe


Sujet :

Développement SQL Server

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Inscrit en
    Avril 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Avril 2013
    Messages : 4
    Points : 1
    Points
    1
    Par défaut Problème sous-requête complexe
    Bonjour, j'ai besoin d'aide pour un problème auquel je n'arrive pas à trouver de solutions.

    Voici ma requête SQL : (j'ai simplifié)

    Select Id, (Ma sous requète) from Table Where (Ma sous requète)<0


    Le problème : Ma sous-requêtes contient des calculs complexes et est calculés pour un très grand nombre de lignes ( plus d'1 millions). C'est déjà très long, et en plus là elle est calculé deux fois.

    Ce que je cherche donc à faire :

    Select Id, (Ma sous requète) AS résultat from Table Where résultat<0

    ou alors :

    Select Id, (Ma sous requète) from Table Where colonne2<0

    Je suppose que vous avez compris le principe.

    Merci

  2. #2
    Expert confirmé
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 242
    Points
    4 242
    Par défaut
    Peut-être regarder du côté de la clause HAVING (à condition d'utiliser une clause GROUP BY).

    Mais sans plus de détails, difficile d'en dire plus (en tout cas pour moi).

  3. #3
    Nouveau Candidat au Club
    Homme Profil pro
    Inscrit en
    Avril 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Avril 2013
    Messages : 4
    Points : 1
    Points
    1
    Par défaut
    Merci de votre réponse. En effet la clause Having n'est pas la solution.
    Désolé du manque de détail, je ne met pas ma requête sur le forum car elle fait 400 lignes. J'ai au contraire préféré simplifié au maximum ma question pour pas que les gens se perdent dans la compréhensions de la requête.

    En gros :
    J'aimerais savoir s'il est possible d'afficher le résultat d'une sous-requête dans mon select alors que cette sous requête a déjà été calculé dans la clause where sans la recalculé.

    Ou alors :

    J'aimerais savoir s'il est possible d'utiliser le résultat d'une sous-requête calculée en tant que colonne dans la clause where sans recalculé la sous-requête.

  4. #4
    Expert confirmé
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 242
    Points
    4 242
    Par défaut
    Et du côté des CTE's, ça donne quoi ?

    Encore une fois, je pense que cela dépend vraiment de ce que vous faites :-/

    Suivant les besoins/contraintes, une solution valide dans un cas peut ne pas convenir dans un autre.

  5. #5
    Nouveau Candidat au Club
    Homme Profil pro
    Inscrit en
    Avril 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Avril 2013
    Messages : 4
    Points : 1
    Points
    1
    Par défaut
    Je n'avais pas pensé au CTEs, c'est une excellente idée. Je vais faire des tests

  6. #6
    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,

    a priori une CTE ne changera pas grand chose. ça permet de factoriser le code mais, comme pour une vue, le moteur remplace la cte par sa définition au moment de l'analyse de la requête. ça resterait cependant un bonne chose pour la lisibilité et la maintenance de la requête.

    Par contre, votre filtre n'est du coup surement pas sargable, et vos lenteurs viennent plutôt de là.

    Même si elle est longue, postez votre requête(merci de l'indenter correctement), on pourra mieux vous aider

  7. #7
    Membre chevronné
    Inscrit en
    Août 2009
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 1 073
    Points : 1 806
    Points
    1 806
    Par défaut
    Pour le cas précis, la CTE ne sera probablement pas applicable (ou alors c'est qu'une jointure aurait pu être faite à la base). Par contre vous pouvez tester un CROSS APPLY :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Select Id, t.valeur from Table CROSS APPLY (Ma sous requète) t
    WHERE t.valeur <0

  8. #8
    Nouveau Candidat au Club
    Homme Profil pro
    Inscrit en
    Avril 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Avril 2013
    Messages : 4
    Points : 1
    Points
    1
    Par défaut
    Bonjour,
    Merci de vos réponse.
    Au sujet du CROSS APPLY : cela fonctionne mais prend beaucoup plus de temps ( environ 15 mn).

    J'ai optimisé au mieux ma requête, elle prend actuellement entre 5 et 7 mn (processeur i7)
    En effet, quasiment aucun filtre n'est sargable.

    Je vous joins ma requète dans un fichier html, c'est plus simple, il vous suffit de faire un glisser-déposer en tant que nouvel onglet.
    Fichiers attachés Fichiers attachés

  9. #9
    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,

    Je n'ai pas regardé toute la requête en détail mais déjà, vous pouvez remplacer ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    WHERE Isnull(ind_annule_lcpt, 0) <> 1
    	AND Isnull(ind_comptable_lcpt, 0) = 1
    	AND Datediff(d, Isnull(reg_date_encaissement_lcpt, date_creat_lcpt), Getdate()) >= 0
    	AND (
    		id_nat_don_cpt = 2
    		OR id_nat_don_cpt = 5
    		OR id_nat_don_cpt = 7
    		OR id_nat_don_cpt = 4
    		)
    	AND id_ctrat = C.id_ctrat
    par cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    WHERE (ind_annule_lcpt IS NULL OR ind_annule_lcpt <> 1)
    	AND ind_comptable_lcpt = 1
    	AND (reg_date_encaissement_lcpt < CAST(GETDATE() + 1 AS DATE) OR (reg_date_encaissement_lcpt IS NULL AND date_creat_lcpt< CAST(GETDATE() + 1 AS DATE) ))
    	AND id_nat_don_cpt IN ( 2,5, 7,4)
    	AND id_ctrat = C.id_ctrat
    et suivre le même principe un peu partout dans votre requête...

  10. #10
    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
    et pour votre question initiale, à savoir la sous requête,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    SELECT TOP 1 CONVERT(DATE, SF.dtrel_statut)
    									FROM statut_fin SF
    									WHERE SF.num_ins = RO.num_ins
    										AND SF.n_statut NOT IN (
    											'BL'
    											,'DB'
    											)
    										AND Datediff(d, CONVERT(DATE, SF.dtrel_statut), @Date2) >= 0
    										AND CONVERT(DATE, SF.dtrel_statut) BETWEEN @Date1
    											AND @Date2
    									ORDER BY SF.dtrel_statut DESC
    Vous pouvez essayer de passer par une CTE avec une fonction de fenetrage :

    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
     
    ;WITH tmp AS (									
    SELECT 
    		CONVERT(DATE, SF.dtrel_statut) AS dtrel_statut
    	,	num_ins
    	,	ROW_NUMBER() OVER (PARTITION BY num_ins ORDER BY dtrel_statut DESC) AS Rn
    FROM	statut_fin
    WHERE	n_statut NOT IN ('BL','DB')
    	AND	dtrel_statut BETWEEN @Date1 AND DATEADD(DAY, 1, @Date2 )
    )	,
    SF AS(
    	SELECT	dtrel_statut
    		,	num_ins
    	FROM	tmp
    	WHERE	rn = 1
    )
    Puis dans votre requête, faites une equi-jointure sur SF avec num_ins...

  11. #11
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Points : 12 371
    Points
    12 371
    Par défaut
    J'ai optimisé au mieux ma requête, elle prend actuellement entre 5 et 7 mn
    Seul le plan réel de requêtes et la sortie de STATISTICS IO, TIME ON, ou une trace sur votre session peut vous l'indiquer

    @++

  12. #12
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 849
    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 849
    Points : 52 978
    Points
    52 978
    Billets dans le blog
    6
    Par défaut
    Pouvez vous faire un IN à la place du NOT IN en mettant les valeurs complémentaire dans la liste ?
    Si oui, créez l'index suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CREATE INDEX X_statut_fin_st_dt_ds ON statut_fin (n_statut, dtrel, num_ins, dtrel_statut);
    Si non, créez l'index suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CREATE INDEX X_statut_fin_st_dt_ds ON statut_fin (dtrel, num_ins, dtrel_statut) INCLUDE (n_statut);
    A +

Discussions similaires

  1. Problème sous requête
    Par darkloy dans le forum Requêtes
    Réponses: 5
    Dernier message: 29/01/2012, 21h35
  2. Utilisation du pivot : problème de requête "complexe"
    Par Kropernic dans le forum Développement
    Réponses: 12
    Dernier message: 27/01/2011, 11h44
  3. Problème sous-requête MAX et COUNT
    Par grafistolage dans le forum Requêtes
    Réponses: 6
    Dernier message: 06/07/2010, 09h08
  4. Problème Sous-Requête
    Par STEF_1 dans le forum Requêtes et SQL.
    Réponses: 2
    Dernier message: 13/01/2006, 13h12
  5. problème sous-requête SQL et order by
    Par aguest dans le forum Requêtes
    Réponses: 10
    Dernier message: 26/12/2005, 23h57

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