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

WinDev Discussion :

Performance interface, requête sql trop longue, inutilisable.


Sujet :

WinDev

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de droliprane
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Mai 2005
    Messages
    710
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2005
    Messages : 710
    Par défaut Performance interface, requête sql trop longue, inutilisable.
    Bonjour à tous,

    maintenant que j'ai migré 2 années de données dans ma gpao "maison" je teste mes interfaces et je me rends compte que ça rame pas mal. Ca vient peut être de la façon dont j'ai construit mes fenêtres, qui comportent systématiquement des tables remplies par requêtage et filtrage via des listes.

    L'exemple ici est l'interface d'interrogation des factures. J'ai migré plus de 4500 factures, et mon interface fait une pagination en n'affichant que 100 lignes à l'écran, et éventuellement on change de page.

    Avant même l'affichage de cet écran, j'attends 20 secondes que ça charge (appli figée ne répond pas), ensuite ça se débloque et je vois ça :



    J'ai testé avec l'analyseur de performances :



    Et ce sont bien les 2 appels à HExécuteRequêteSQL qui consomment les 99,9% du temps de chargeFactures (voir code plus bas).

    Pourtant ma requête est sensée me ramener seulement 100 lignes, ce qui n'est quand même pas le bout du monde. Alors je m'interroge sur le pourquoi de cette lenteur. Je me permets de coller le code la procédure chargeFactures, qui s'exécute chaque fois que je tape dans un champs ou que je sélectionne dans une liste.... J'ai essayé de la threader mais c'est encore plus long (affichage progressif mais très lent) !

    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
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    PROCEDURE chargeFactures(LOCAL page_selectionnee est un entier = 1)
     
     
    nb_requetes ++
    // ça c'est pour ne pas exécuter la procédure inutilement à l'initialisation de l'interface
    // car elle est déclenchée sur sélection d'un élément de chacune des listes Client, Commande ou Article 
    // ici, ignore_n_premieres_requetes vaut 3
    SI nb_requetes <= ignore_n_premieres_requetes ALORS RETOUR  
     
    TableSupprimeTout(TABLE_Factures)
     
    criteres est une chaîne = ""
    criteres2 est une chaîne = ""
     
    img est une chaîne = ""
     
    SI LISTE_Commandes > 0 ALORS 
    	criteres = " WHERE cc_id = " + LISTE_Commandes
    SINON
    	SI SAI_filtre1 <> "" ALORS
    		criteres = " WHERE cc_num LIKE '%" + Replace(SAI_filtre1, "*", "%") + "%'"
    	SINON
    		// critere pour obligatoirement avoit un WHERE
    		criteres = " WHERE fcl_id > 0"
    	FIN
    FIN
     
    SI LISTE_Articles > 0 ALORS 
    	criteres = criteres + " AND art_id = " + LISTE_Articles
    SINON
    	SI SAI_filtre2 <> "" ALORS
    		criteres = criteres + " AND (art_reference LIKE '%" + Replace(SAI_filtre2, "*", "%") + "%' OR (fcl_article_id = 0 AND fcl_commentaire LIKE '%" + Replace(SAI_filtre2, "*", "%") + "%'))"
    	FIN
    FIN
     
    SI LISTE_Clients > 0 ALORS
    	criteres2 = "AND clt_id = " + LISTE_Clients
    SINON
    	criteres2 = "AND clt_code LIKE '%" + Replace(SAI_filtre, "*", "%") + "%'"
    FIN
     
     
    // PREMIERE REQUETE POUR CONNAITRE LE NOMBRE DE PAGES
    Sql est une chaîne = "SELECT count(fc_id) AS nblignes FROM fc,clt, dev " + 
    "WHERE fc_id IN (SELECT DISTINCT fcl_fc_id FROM " +
    "(((fcl FULL OUTER JOIN cc ON fcl_bl_cc_id = cc_id) " +
    "FULL OUTER JOIN ccl ON  fcl_bl_ccl = ccl_ligne) " +
    "FULL OUTER JOIN art ON fcl_article_id = art_id) " +
    criteres + ") AND fc_client = clt_id AND fc_devise = dev_id " + criteres2
     
     
    Rs est une Source de Données
    nblignes est un entier = 0
    nbpages est un entier = 1
    SI PAS HExécuteRequêteSQL(Rs,Cnx,hRequêteSansCorrection,Sql) ALORS
    	Erreur("Erreur d'initialisation de la requête"+RC+HErreurInfo()+ RC + RC + Sql)
    	RETOUR
    FIN
    SI HLitPremier(Rs) ALORS
    	nblignes = Rs.nblignes
    FIN
    HLibèreRequête(Rs)
     
    //info(nblignes)
     
     
    critere_pagination est une chaîne = ""
    SI COMBO_nb_lignes..ValeurAffichée <> "TOUT" ALORS
    	premiere_ligne est un entier = ((page_selectionnee - 1) * Val(COMBO_nb_lignes..ValeurAffichée) + 1)
    	derniere_ligne est un entier = premiere_ligne + Val(COMBO_nb_lignes..ValeurAffichée) - 1
    	critere_pagination = "WHERE a.ligne >= " + premiere_ligne + " AND a.ligne <= " + derniere_ligne
     
    	nbpages = PartieEntière(nblignes / Val(COMBO_nb_lignes..ValeurAffichée))
    	SI PartieDécimale(nblignes / Val(COMBO_nb_lignes..ValeurAffichée)) > 0 ALORS
    		nbpages ++
    	FIN
    	SI nbpages = 0 ALORS nbpages = 1
    FIN
     
    LIB_nbpages = "/ " + nbpages
    ListeSupprimeTout(COMBO_page)
    POUR i = 1 _A_ nbpages
    	ListeAjoute(COMBO_page,i)
    FIN
    ListeSelectPlus(COMBO_page,page_selectionnee)
     
     
    Sql = "SELECT* FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY fc_id Desc) AS ligne FROM fc,clt, dev " + 
    "WHERE fc_id IN (SELECT DISTINCT fcl_fc_id FROM " +
    "(((fcl FULL OUTER JOIN cc ON fcl_bl_cc_id = cc_id) " +
    "FULL OUTER JOIN ccl ON  fcl_bl_ccl = ccl_ligne) " +
    "FULL OUTER JOIN art ON fcl_article_id = art_id) " +
    criteres + ") "+
    "AND fc_client = clt_id AND fc_devise = dev_id " + criteres2 + ") a  " + critere_pagination
     
    //trace(Sql)
     
     
    SI PAS HExécuteRequêteSQL(Rs,Cnx,hRequêteSansCorrection,Sql) ALORS
    	Erreur("Erreur d'initialisation de la requête"+RC+HErreurInfo()+ RC + RC + Sql)
    	RETOUR
    FIN
    SI HLitPremier(Rs) ALORS
     
    	TANTQUE PAS HEnDehors(Rs)
     
    		img = "delete.png"
    		TableAjoute(TABLE_Factures, Rs.fc_id + TAB + Rs.fc_num + TAB + Rs.clt_code + TAB + Rs.fc_total_ht + TAB + Rs.fc_taux_tva + TAB + Rs.fc_total_tva + TAB + Rs.fc_total_ttc + TAB + Rs.fc_emballage + TAB + Rs.fc_port + TAB + Rs.fc_assurance + TAB + Rs.fc_total_facture + TAB + Rs.dev_nom + TAB + Rs.fc_date + TAB + img)
    		HLitSuivant(Rs)
    	FIN
     
    FIN
     
    HLibèreRequête(Rs)
     
     
    SI TABLE_Factures..Vide ALORS
    	BTN_IMPRIMER..Grisé = Vrai
    SINON
    	BTN_IMPRIMER..Grisé = Faux
    FIN
    Ensuite quand j'essaye d'interagir avec l'interface, par exemple commencer à saisir un nom de client, ça prend entre 5 et 10 secondes à chaque caractère tapé, avant de retrouver la main dans le champs de saisie...

    Bref, c'est pas possible de faire bosser les gens comme ça.

    Il faut que je trouve une solution rapidement, j'aimerais déployer mon appli fin Janvier.

    Toute aide est la bienvenue, merci d'avance.


    EDIT : ça semble venir de la construction de ma requête Sql (la deuxième, la plus complexe à mon avis) car à titre de comparaison j'ai un écran d'interrogation des livraisons, qui me ramène encore d'avantage de lignes (125 pages de 100 lignes) et l'écran se charge initialement en moins de 3 secondes et se réactualise assez bien à chaque saisie...

  2. #2
    Membre éclairé Avatar de droliprane
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Mai 2005
    Messages
    710
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2005
    Messages : 710
    Par défaut
    Ca semble venir des deux requêtes, tant celle qui sert à compter le nombre de factures, que celle qui les affiche

    J'ai testé mes requêtes directement dans SQL Server, et la première (comptage) met 7-8 secondes à retourner le résultat

    La seconde, met environ 15 secondes à chaque fois

    Soit il est possible de construire mieux mes requêtes, soit je stocke dans ma table fcl (lignes de factures) des champs redondant avec les données qui existent dans les tables liées, mais ce qui m'éviterait de faire toutes ces jointures...

    A savoir la référence article et le numéro de commande, stockés dans la ligne de facture, simplement pour faciliter le requêtage dans cet écran....

    Je vais tester

  3. #3
    Membre Expert
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2009
    Messages
    1 278
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2009
    Messages : 1 278
    Par défaut
    Je ne suis pas étonné d'apprendre que les requêtes sont très longues à s'exécuter....

    Plusieurs raisons à ça :

    -> des likes partout (sont-ils vraiment nécessaire ?)
    -> un IN dans le WHERE (si vous pouvez passer par une jointure, ça serait mieux)
    -> des FULL OUTER JOIN dans les sous-requêtes... (sont-ils vraiment nécessaire ? si oui c'est que votre modèle présente des étrangetés !)

  4. #4
    Membre éclairé Avatar de droliprane
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Mai 2005
    Messages
    710
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2005
    Messages : 710
    Par défaut
    Bonjour

    Les LIKE oui c'est une demande particulière de ma boite, je conçois que ça alourdit le temps de traitement

    Le IN si je fais une jointure (entre tablle fc et fcl) je ne pourrai plus compter les factures seules car j'aurai démultiplié les résultats avec les lignes de chaque facture

    Les OUTER JOIN sont là car je permets d'avoir sur une facture une ligne qui ne soit pas rattachée à un BL (et donc une commande/ligne/article), donc je veux chercher dans toutes les lignes de factures, même celles qui sont orpheline d'un BL...

  5. #5
    Expert confirmé
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 441
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 441
    Par défaut
    Bonjour,
    Vu les requêtes, j'imagine que c'est du SQL Server.
    Je note aussi que les deux requêtes se ressembles furieusement.
    Est-ce que tu ne peux pas passer par une vue matérialisée ?

    Tatayo.

  6. #6
    Membre Expert
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2009
    Messages
    1 278
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mars 2009
    Messages : 1 278
    Par défaut
    D'après ce que vous dites vous devriez faire des LEFT JOIN mais pas de FULL OUTER JOIN...

Discussions similaires

  1. [Débutant] Requête SQL Trop longue
    Par Avatar69 dans le forum C#
    Réponses: 3
    Dernier message: 14/05/2013, 18h26
  2. Temps d'exécution requête SQL trop Longue
    Par farouk1301 dans le forum JDBC
    Réponses: 7
    Dernier message: 09/08/2012, 20h25
  3. [MySQL] Interrompre une requête sql trop longue
    Par kayoum dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 30/05/2011, 14h00
  4. Probleme de requête SQL trop longue
    Par piscou51000 dans le forum Requêtes
    Réponses: 4
    Dernier message: 13/02/2010, 19h06
  5. [Requête SQL]Trop longue pour une ligne
    Par jbulysse dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 17/07/2008, 14h27

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