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

VB.NET Discussion :

Problème de temps de réponse pour une recherche d'articles


Sujet :

VB.NET

  1. #1
    Membre à l'essai
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Novembre 2011
    Messages : 13
    Points : 11
    Points
    11
    Par défaut Problème de temps de réponse pour une recherche d'articles
    J'ai un problème de temps de réponse pour la recherche d'articles. Comment revenir à un temps de réponse acceptable (max. 1 à 2 min)?

    Dans le programme il y a un system de recherche pour les articles. Quand on fait un recherche précise (exemple sur le nom ou le fournisseur), la pas trop de problèmes. Par contre quand on fait un recherche globale, c'est à dire qu'on veut voir tout les articles dans la DB, ben la ça prend beaucoup plus de temps. Le temps qu'il compile toutes les données ça peut prendre plusieurs minutes , il faut aussi savoir qu'il peut y avoir plus de 100.000 articles dans la DB (chez certain client ça dépasse les 300.000 articles).
    Les données sont aussi répartis sur plusieurs tables, donc l'Sql pour aller rechercher tout ça est assez complexe (enfin pour moi).

    Oubliez l'archivage car je ne peut pas archiver les articles pour raison d'historique. Il faut que les données soient consultables jusqu'à 10 ans en arrière (merci le fisc) .

    J'avais pensé au multi-threading avec d'abord un petit sql qui fait un retour de max 200 lignes par exemple et faire la suite en arrière plan (avec un autre thread mais je ne trouve pas d'exemple claire comment faire ça et je débute en programmation vb.net . Mais je suis pas sur que se soit la solution.

    Je dois aussi faire tourner tout ça sur un bon PC et pas sur un serveur. Le client refusant de payer un machine de 5000€ ou plus . Leur budget étant toujours très très limité, le grand classique quoi ils veulent tout pour tout pour rien.

    Pour la DB j'utilise Sql express 2005 et le programme est écrit en VB.net avec Visual studio 2005.

    Bon voila j'espère que les données du problème sont claires. Je suis ouvert à toutes suggestions, pistes, exemples,... pour solutionner ce problème.

    d'avance merci

  2. #2
    Membre expérimenté Avatar de hunteshiva
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Février 2010
    Messages
    1 069
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2010
    Messages : 1 069
    Points : 1 455
    Points
    1 455
    Par défaut
    Bonjour,

    un budget serré en période de crise ça parait être normale

    Si je comprend bien, tu a une base SQL *grosse base*
    et les recherches sont un peux longues à venir.

    peux tu nous donner un aperçu des requêtes SQL faites ainsi que la structure de la BDD.

  3. #3
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 154
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    J'ai l'impression que ton problème vient de la recherche "globale".

    A quoi bon retourner 100 000 lignes ? (ou même 300 000 ?)

    Dans un premier temps, utilise la pagination (pour ne récupérer à l'écran que 100 lignes, ce sera déjà bien suffisant)

    Et bloque dans tous les cas le nombre de lignes retournées à 1 000 ou 10 000, en mettant un TOP dans la requête :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SELECT TOP 1000 ...
    from ...
    En effet, il y a trois éléments qu'il faut prendre en compte :
    - Le temps d'exécution de la requête SQL
    - Le temps de transfert des données vers l'application
    - Le temps d'affichage des données dans l'application

    SQL Server, même si c'est une version Express sur une machine pourrie, est fait pour traiter de gros volumes de données.
    300 000 lignes, même si c'est important, reste un grain de sable par rapport aux capacités de SQL Server.
    Donc même avec une requête assez complexe, retrouver 300 000 lignes ne devrait pas excéder quelques dizaines de secondes.

    En revanche, ensuite le SGBD doit envoyer les données à l'application : 300 000 lignes, c'est tout de suite quelques Mo à transférer. Selon la charge du réseau, ça apporte quelques secondes de plus.

    Enfin, et c'est là que c'est le pire : l'affichage. Si tu affiches par exemple dans un DataGridView, le programme va devoir charger l'intégralité des données en mémoire. Les objets sont rapidement très volumineux, d'autant que des contrôles sont effectués sur la cohérence (types, largeur des colonnes, etc.)
    Avec un tel volume de données, normal que l'application soit à genoux. Là, ça peut rapidement prendre plusieurs minutes, surtout si tu commence à swapper par manque de mémoire !

    D'où l'intérêt de limiter le nombre de lignes retournées par la requête : l'application ne va plus passer son temps à traiter des données qui ne seront de toute façon jamais affichées.
    On ne jouit bien que de ce qu’on partage.

  4. #4
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Février 2003
    Messages
    2 177
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2003
    Messages : 2 177
    Points : 4 489
    Points
    4 489
    Par défaut
    Citation Envoyé par Tazze-99 Voir le message
    J'ai un problème de temps de réponse pour la recherche d'articles. Comment revenir à un temps de réponse acceptable (max. 1 à 2 min)?

    Dans le programme il y a un system de recherche pour les articles. Quand on fait un recherche précise (exemple sur le nom ou le fournisseur), la pas trop de problèmes. Par contre quand on fait un recherche globale, c'est à dire qu'on veut voir tout les articles dans la DB, ben la ça prend beaucoup plus de temps. Le temps qu'il compile toutes les données ça peut prendre plusieurs minutes , il faut aussi savoir qu'il peut y avoir plus de 100.000 articles dans la DB (chez certain client ça dépasse les 300.000 articles).
    Les données sont aussi répartis sur plusieurs tables, donc l'Sql pour aller rechercher tout ça est assez complexe (enfin pour moi).

    Oubliez l'archivage car je ne peut pas archiver les articles pour raison d'historique. Il faut que les données soient consultables jusqu'à 10 ans en arrière (merci le fisc) .

    J'avais pensé au multi-threading avec d'abord un petit sql qui fait un retour de max 200 lignes par exemple et faire la suite en arrière plan (avec un autre thread mais je ne trouve pas d'exemple claire comment faire ça et je débute en programmation vb.net . Mais je suis pas sur que se soit la solution.

    Je dois aussi faire tourner tout ça sur un bon PC et pas sur un serveur. Le client refusant de payer un machine de 5000€ ou plus . Leur budget étant toujours très très limité, le grand classique quoi ils veulent tout pour tout pour rien.

    Pour la DB j'utilise Sql express 2005 et le programme est écrit en VB.net avec Visual studio 2005.

    Bon voila j'espère que les données du problème sont claires. Je suis ouvert à toutes suggestions, pistes, exemples,... pour solutionner ce problème.

    d'avance merci
    Euh le fisc n'interdit pas l'archivage et il y a plusieurs moyens de faire
    1) Sauvegarder les données anciennes avant de les purgers
    2) Mettre dans des tables distinct les vieux records et faire un lien uniquement quand il y a besoin
    3) Mettre en place 2 bases de données. Une avec toutes les données et une autre avec les données récentes qui sera utilisée pour le travail quotidien.
    4) Faire un vrai datawarehouse, car en général le fisc et l'entreprise n'a pas besoin de toutes les informations mais que d'une partie (exemple tu stocks peut-être les information sur les dimension d'un produit qui ne servent plus à grand chose 5 ans après ou bien supprimer les produits que tu n'as jamais vendu, les informations sur le stock,...)

    et sinon il y a aussi la solution de stringbuilder un top 100 si tu n'affiches que 100 records à l'écran et utiliser un curseur et l'utilisation de thread pour que l'application semble plus réactive mais ca ne changera rien au temps pour lire les records
    Je ne suis qu'un pauvre débutant alors ne frappez pas si mes idées ne sont pas bonnes

  5. #5
    Membre à l'essai
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Novembre 2011
    Messages : 13
    Points : 11
    Points
    11
    Par défaut
    re bonjour

    ci-joint un exemple de requete sql (oui je sais c'est une sacré tartine )

    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
     
    Select  ite.ItemExtnumber , Ite.colRoot , Ite.wsroot  , Ite.ItemExtCode ,   De_itm.MultiDescription , p.p_01 , s.s_Qty , Itm.ItemMainDesc2 ,  Itm.ItemMainType
    From  ItemExts as Ite 
    Left Outer Join ItemMains as itm ON (Ite.ItemExtMain = Itm.ItemMainNumber AND Ite.ItemExtMainCol = Itm.ColRoot AND Ite.ItemExtMainWs = Itm.WsRoot )  
    Left Outer Join Descriptions as de_itm ON ( Itm.ItemMainNumber = De_itm.MultiCode AND Itm.ColRoot = De_itm.MultiCodeCol AND Itm.WsRoot = De_itm.MultiCodeWs 
     and de_itm.MultiTable = 5 and de_Itm.multilang = 1 and de_Itm.Multilangcol = 0 and de_itm.Multilangws = 0 ) 
     Left Outer Join Units as un  ON (itm.itemmainunit = un.unitnumber AND itm.itemmainunitcol = un.colroot AND itm.itemmainunitws = un.wsroot)  
     Left Outer Join Descriptions as de_Un on (un.unitNumber = de_un.MultiCode AND un.ColRoot = de_un.MultiCodeCol AND un.WsRoot = de_un.MultiCodeWs 
     and de_un.multiTable = 24 and de_un.Multilang = 1 and de_un.multilangcol = 0 and de_un.multilangws = 0 ) 
     Left Outer Join Seasons as se  ON (itm.itemmainseason = se.seasonnumber AND itm.itemmainseasoncol = se.colroot AND itm.itemmainseasonws = se.wsroot)  
     Left Outer Join Descriptions as de_Se on (se.seasonNumber = de_se.MultiCode AND se.ColRoot = de_se.MultiCodeCol AND se.WsRoot = de_se.MultiCodeWs 
     and de_se.multiTable = 30 and de_se.Multilang = 1 and de_se.multilangcol = 0 and de_se.multilangws = 0 ) 
     Left Outer Join brands as br on (itm.itemmainbrand = br.brandnumber and itm.itemmainbrandcol = br.colroot and itm.itemmainbrandws = br.wsroot) 
     Left Outer Join Descriptions as de_br on (br.brandnumber = de_br.multicode and br.colroot = de_br.multicodecol and br.wsroot = de_br.multicodews 
     and de_br.multitable = 82 and de_br.multilang = 1 and de_br.multilangcol = 0 and de_br.multilangws = 0 ) 
     Left Outer Join Documents as do on ( Itm.itemMainLabel = do.documentnumber and itm.itemmainlabelcol = do.colroot and itm.itemmainLabelws = do.wsroot ) 
     Left Outer Join Descriptions as de_do on (do.documentnumber = de_do.multicode and do.colroot = de_do.multiCodecol and do.wsroot = de_do.multicodews 
     and de_do.MultiTable = 102 and de_do.multilang = 1 and de_DO.multilangcol = 0 and de_do.multilangws = 0 ) 
     Left Outer Join families as fa on ( itm.itemmainFamily = fa.familynumber and itm.itemmainfamilycol = fa.colroot and itm.itemmainfamilyws = fa.wsroot ) 
     Left Outer Join familyDefs as fa_gr on ( fa.familyGroup = fa_gr.familydefnumber and fa.familyGroupCol = fa_gr.colroot and fa.familyGroupws = fa_gr.wsroot ) 
     Left Outer Join Descriptions as de_fa_gr on ( fa_gr.familydefnumber = de_fa_gr.multicode and fa_gr.colroot = de_fa_gr.multicodecol and fa_gr.wsroot = de_fa_gr.multicodews 
     and de_fa_gr.multitable = 90 and de_fa_gr.multilang = 1 and de_fa_gr.multilangcol = 0 and de_fa_gr.multilangws = 0 ) 
     Left Outer Join familyDefs as fa_sg on ( fa.familysGroup = fa_sg.familydefnumber and fa.familysGroupCol = fa_sg.colroot and fa.familysGroupws = fa_sg.wsroot ) 
     Left Outer Join Descriptions as de_fa_sg on ( fa_sg.familydefnumber = de_fa_sg.multicode and fa_sg.colroot = de_fa_sg.multicodecol and fa_sg.wsroot = de_fa_sg.multicodews 
     and de_fa_sg.multitable = 90 and de_fa_sg.multilang = 1 and de_fa_sg.multilangcol = 0 and de_fa_sg.multilangws = 0 ) 
     Left Outer Join familyDefs as fa_de on ( fa.familydepart = fa_de.familydefnumber and fa.familydepartCol = fa_de.colroot and fa.familydepartws = fa_de.wsroot ) 
     Left Outer Join Descriptions as de_fa_de on ( fa_de.familydefnumber = de_fa_de.multicode and fa_de.colroot = de_fa_de.multicodecol and fa_de.wsroot = de_fa_de.multicodews 
     and de_fa_de.multitable = 90 and de_fa_de.multilang = 1 and de_fa_de.multilangcol = 0 and de_fa_de.multilangws = 0 ) 
     Left Outer Join qtyDiscounts as qd on ( itm.itemmainQtyDisc = qd.qtyDiscountnumber and itm.itemMainQtyDisccol = qd.colroot and itm.itemmainqtydiscws = qd.wsroot ) 
     Left Outer Join Descriptions as de_Qd on ( qd.qtydiscountnumber = de_qd.multicode and qd.colroot = de_qd.multicodecol and qd.wsroot = de_qd.multicodews 
     and de_qd.multitable = 95 and de_qd.multilang = 1 and de_qd.multilangcol = 0 and de_qd.multilangws = 0 ) 
     LEFT OUTER JOIN ( 
     Select sum(case T.TariffOrder when 1 then P.ItemPricePrice else 0 end ) as P_01 ,  
     sum(case T.TariffOrder when 2 then P.ItemPricePrice else 0 end ) as P_02 , 
     sum(case T.TariffOrder when 3 then P.ItemPricePrice else 0 end ) as P_03 ,  
     sum(case T.TariffOrder when 4 then P.ItemPricePrice else 0 end ) as P_04 ,  
     sum(case T.TariffOrder when 5 then P.ItemPricePrice else 0 end ) as P_05 ,   
     P.ItemPriceItemExt as p_Id , P.ItemPriceItemextCol as p_Col , P.ItemPriceItemextws as p_Ws  
     FROM ItemPrices as P 
     Left Outer Join  Tariffs as T on ( p.ItemPriceTariff = t.Tariffnumber and p.ItemPriceTariffCol = t.Colroot and p.ItemPriceTariffWs = t.wsroot ) 
     Left Outer Join  ProfilePrices as pp on ( t.TariffPrices = pp.priceNumber and t.TariffPricesCol = pp.colroot  and t.TariffPricesWs = pp.wsroot ) 
     Left Outer Join  objectlist as ol on ( ol.objectcolprices = pp.PriceProfile and ol.objectcolpricescol = pp.PriceProfilecol and ol.objectcolpricesws = pp.PriceProfileWs )  
     where ol.objectcolnumber = 1
     group by p.ItemPriceItemext , p.ItemPriceItemExtCol, p.ItemPriceItemExtWs  
     ) as p on ( p_id = Ite.ItemExtnumber and p_col = Ite.colroot and p_ws = Ite.wsroot ) 
     Left Outer Join ItemQties as itq on ( itq.itemQtyItemExt = ite.ItemExtnumber and itq.itemQtyItemExtcol = ite.colroot and itq.itemQtyItemExtws = ite.wsroot and itq.itemQtycollect = 1 ) 
     Left Outer Join ItemStocks as its on ( Its.ItemStockItemQty  = itq.itemQtyNumber and Its.ItemStockItemQtycol = itq.colroot and its.ItemStockItemQtyws = itq.wsroot ) 
     Left Outer Join ( 
     Select  
     ( Case when s1_Qty is null then s2_Qty else s1_Qty end ) as s_Qty 
     , ( case when s1_Ordered is null then  s2_Ordered else s1_ordered end ) as s_Ordered 
     , ( case when s1_Reserved is null then s2_reserved else s1_Reserved end ) as s_REserved 
     , ( case when s1_Consig is null then s2_Consig else s1_Consig end ) as s_Consig 
     , ( case when s1_Call is null then s2_Call else s1_Call end ) as s_Call 
     , ( case when s1_Ask is null then s2_Ask else s1_Ask end ) as s_Ask 
     , ( case when s1_Transfer is null then s2_Transfer else s1_Transfer end ) as s_Transfer 
     , ( case when s1_Label is null then s2_Label else s1_Label end ) as s_Label 
     , ( case when s2_Min is null then 0 else s2_Min end ) as s_min 
     , ( case when s2_Max is null then 0 else s2_Max end ) as s_Max  
     , ( case when s2_Place is null then '' else s2_Place end ) as s_Place 
     , ( case when s2_Volume is null then 0 else s2_volume end ) as s_volume 
     , ( case when s2_Brut  is null then 0 else s2_Brut end ) as s_Brut 
     , ( case when s2_net is null then 0 else s2_Net end ) as s_net 
     , ( ( Case when s1_Qty is null then s2_Qty else s1_Qty end ) - 
     ( case when s1_Reserved is null then s2_reserved else s1_Reserved end ) - 
     ( case when s1_Consig is null then s2_Consig else s1_Consig end ) ) as s_QtyFree 
     , Itq.ItemQtyItemExt as s_Id 
     , Itq.ItemQtyItemExtCol as s_Col 
     , Itq.ItemQtyItemExtWs as s_Ws 
     From ItemQties as Itq  
     Left outer join ( 
     Select 
     sum (ItS.ItemStockQty) as s1_Qty  
     , sum (Its.ItemStockOrdered) as s1_Ordered 
     , sum (Its.ItemStockReserved) as s1_Reserved 
     , sum( Its.ItemStockConsig) as s1_Consig 
     , sum( Its.ItemStockCall) as s1_Call 
     , sum( Its.ItemStockAsk) as s1_Ask 
     , sum( Its.ItemStockTransfer) as s1_Transfer 
     , sum( Its.ItemStockLabelQty) as s1_Label 
     , Itq.ItemQtyItemExt as s1_Id 
     , Itq.ItemQtyItemExtCol as s1_Col 
     , Itq.ItemQtyItemExtWs as s1_ws  
     from ItemStocks as Its 
     Left Outer Join ItemQties as Itq on ( Itq.ItemQtynumber = Its.ItemStockItemQty and itq.colroot = Its.ItemStockItemQtyCol and Itq.wsroot = Its.ItemStockItemQtyWs ) 
     Left Outer Join ShopConnected as SC on ( SC.ShopLinked = Itq.ItemQtyCollect ) 
     where SC.ShopVirtual = 1
     Group by Itq.ItemQtyItemExt , Itq.ItemQtyItemExtCol , Itq.ItemQtyItemExtWs  
     ) as s1 on ( s1_Id = Itq.ItemQtyItemExt and s1_Col = Itq.ItemQtyItemExtCol and s1_Ws = Itq.ItemQtyItemExtWs ) 
     left outer join ( 
     Select 
     Its.ItemStockQty as s2_Qty 
     , Its.ItemStockOrdered as s2_Ordered 
     , Its.ItemStockReserved as s2_REserved 
     , Its.ItemStockConsig as s2_Consig 
     , Its.ItemStockCall as s2_Call 
     , Its.ItemStockAsk as s2_Ask 
     , Its.ItemStockTransfer as s2_Transfer 
     , Its.ItemStockLabelQty as s2_Label 
     , Its.ItemStockMin as s2_Min 
     , Its.ItemStockMax as s2_Max 
     , Its.ItemStockPlace as s2_Place 
     , Its.ItemStockVolume as s2_Volume 
     , Its.ItemStockBrut as s2_Brut 
     , Its.ItemStockNet as s2_net 
     , Itq.ItemQtyItemExt as s2_Id 
     , Itq.ItemQtyItemExtCol as s2_Col 
     , Itq.ItemQtyItemExtWs as s2_Ws 
     From ITemStocks as Its 
     Left Outer Join ItemQties as itq on ( itq.ItemQtynumber = its.ItemStockItemQty and itq.colroot = its.ItemStockItemQtyCol and itq.wsroot = its.ItemStockItemQtyWs ) 
     where Itq.ItemQtyCollect = 1  ) 
     as s2 on ( s2_Id = Itq.ItemQtyItemExt and s2_Col = Itq.ItemQtyItemExtCol and s2_Ws = Itq.ItemQtyItemExtWs ) where Itq.ItemQtyCollect = 1
     ) as s on ( s_id = Ite.ItemExtnumber and s_col = Ite.colroot and s_ws = Ite.WsRoot ) 
     
     Where Itm.ColDelete = 0 and Ite.ColDelete  = 0  and ( (( ((  Itm.ItemMainType = 0
     )) )) ) 
     Order By De_itm.MultiDescription Asc
    L'sql est généré dans un module qui est utilisé dans tout le programme, de la la disproportion entre les champs préparés et les champs utilisés. Les champs utilisés sont aussi sélèctionés en fonction de ce que le client veut avoir comme résultat sur l'écran.
    Jai été un ptit peu fainéant sur ce coup là en créant une procédure qui construit l'sql dynamiquement, plutôt que 100 sql écrit en dur dans le programme. Dons je dois encore affiner la procedure.

    La structure de la Db serait trop longue et trop volumineuse pour la donner.
    Pour faire simple il existe 20 tables différentes pour les articles où les données sont stockées. description, prix, stock, lient magasin stock , ... avec chacune un clé primaire et des indexes secondaires.
    au total il y a +/- 200 tables dans la DB

  6. #6
    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 239
    Points
    4 239
    Par défaut
    OMG la requête !!!

    Ce ne serait pas plus intéressant pour toi d'aller chercher de l'aide sur le forum sql (server?) ?

    Ah moins que tu n'aies pas le droit de modifier cette requête, il doit sûrement y avoir moyen de l'optimiser.
    Kropernic

  7. #7
    Membre à l'essai
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Novembre 2011
    Messages : 13
    Points : 11
    Points
    11
    Par défaut
    a Stringbuilder

    j'avais pensé à cette solution, mais le problème est que certaines personnen veulent tout voir grrrrrrrr . Je suis certain que si je place un top 1000 ils voudront voir la ligne 1001. Où y a t'il moyen de dire a SQL retourne moi les ligne 1001 a 2000. je crois que c'est possible dans mysql.

    a BenoitM

    t'on idée me semble intérressante, faire une DB avec les données récente et une autre pour l'archivage mais comment dois-je faire pour faire fonctionner les deux ensemble. Je n'ai encore jamais fait du datawarehousing.
    aurais-tu un lien ou exemple a me proposer pour que je comprenne bien le concepte .

  8. #8
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Points : 13 314
    Points
    13 314
    Par défaut
    Selon toute vraissemblance, le problème vient de la base.

    Les index ont il été correctement définis ?

    As tu optimisé l'usage des index "cluster" sur les champs les plus utilisés en recherche ?

    Rappel : en SQL SERVER, RIEN n'oblige à utiliser la PK comme 'cluster index' d'une table - même si par défaut c'est la PK qui est utilisé pour cela et que dans 90% des cas ce choix n'est pas optimal.

    etc .....

    De plus, le SQL dynamique empêche le moteur de base d'utiliser un certain nombre d'optimisations.

    Uen recherche sur 100 ou 200 000 lignes n'a a priori aucune raison de prendre les temps que tu indiques (> 2mn).

    Je ne réponds pas aux questions techniques par MP ! Le forum est là pour ça...


    Une réponse vous a aidé ? utiliser le bouton

    "L’ennui dans ce monde, c’est que les idiots sont sûrs d’eux et les gens sensés pleins de doutes". B. Russel

  9. #9
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Février 2003
    Messages
    2 177
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2003
    Messages : 2 177
    Points : 4 489
    Points
    4 489
    Par défaut
    Tu peux déjà créer des vues
    Tu peux surement généré dynamiquement les recherches
    (rien ne sert de voir une jointure avec la table prix si l'utilisateur ne demande pas le prix dans ses critère de recher)

    comme dit plus haut penser au index

    le but n'est pas de limiter le nombre à 100 record, mais de parcourir les champs par 100 records.

    Comme les pages web en général, tu changes de pages pour voir la suite

    Faire 2 vue, une qui affiches les champs principeaux , et une qui affiche le tout.

    Voir si le nombre de table est vraiment utile
    Je ne suis qu'un pauvre débutant alors ne frappez pas si mes idées ne sont pas bonnes

  10. #10
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 154
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Tazze-99 Voir le message
    a Stringbuilder

    j'avais pensé à cette solution, mais le problème est que certaines personnen veulent tout voir grrrrrrrr . Je suis certain que si je place un top 1000 ils voudront voir la ligne 1001. Où y a t'il moyen de dire a SQL retourne moi les ligne 1001 a 2000. je crois que c'est possible dans mysql.
    Le LIMIT de MySQL n'existe pas avec SQL Server.

    Cependant, tu peux le simuler (c'est un peu barbare, mais niveau performances c'est tout à fait correct)

    http://sqlserver.developpez.com/faq/?page=Jeu#Jeu2
    On ne jouit bien que de ce qu’on partage.

  11. #11
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Février 2003
    Messages
    2 177
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2003
    Messages : 2 177
    Points : 4 489
    Points
    4 489
    Par défaut
    Citation Envoyé par Tazze-99 Voir le message
    a Stringbuilder

    t'on idée me semble intérressante, faire une DB avec les données récente et une autre pour l'archivage mais comment dois-je faire pour faire fonctionner les deux ensemble. Je n'ai encore jamais fait du datawarehousing.
    aurais-tu un lien ou exemple a me proposer pour que je comprenne bien le concepte .
    C'est plus du domaines des DBA
    Il faut poser la questions dans le forum pour sql serveur
    Je ne suis qu'un pauvre débutant alors ne frappez pas si mes idées ne sont pas bonnes

  12. #12
    Membre à l'essai
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Novembre 2011
    Messages : 13
    Points : 11
    Points
    11
    Par défaut
    OK si j'ai bien compris c'est plus un problème au niveau de l'Sql que de la programmation.
    Je vais essayer d'optimiser la requête et trouver des info sur les indexes, vues, ... dans le forum sql.

    L'idée de parcourir les champs par 100 records me semble excellente mais je vois pas du tout comment la mettre en pratique. A moins d'arriver a faire comprendre à sql qu'il doit m'envoyer un certain morceau du résultat global. (de la ligne 100 as 150 par exemple) A ce moment la je peux générer un event sur la touche page down / page up qui lancerait un requête plus ciblé que le gros bazar que je lance actuellement.
    Solution a creuser

    Merci pour l'aide

  13. #13
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 154
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Aussi, je rejoins les autres commentaires quant à la requête :
    - Modifie ton module de génération de requête pour ne faire des jointures que lorsque c'est nécessaire
    - Evite comme la peste les LEFT OUTER JOIN : C'est bien plus lent qu'un INNER JOIN
    - Les FK sont-elles correctement déclarées ?
    - Essaye de passer par des vues (certaines informations sont systématiquement liées (par exemple, famille/sous-famille) et on souhaite généralement toujours les avoir. Donc au lieu de faire une jointure sur famille puis sous-famille, on peut faire une vue qui ramène les deux, et faire une jointure dessus : ce sera plus rapide.
    On ne jouit bien que de ce qu’on partage.

  14. #14
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 154
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par StringBuilder Voir le message
    Le LIMIT de MySQL n'existe pas avec SQL Server.

    Cependant, tu peux le simuler (c'est un peu barbare, mais niveau performances c'est tout à fait correct)

    http://sqlserver.developpez.com/faq/?page=Jeu#Jeu2
    Aussi, avec ADO et VB6, je me souvient qu'on pouvait demander à ADO de faire la pagination automatique. Je ne me suis jamais penché sur la question avec ADO.NET, mais il est fort à parier que la fonctionnalité existe encore.
    Après, à voir niveau performances.
    On ne jouit bien que de ce qu’on partage.

  15. #15
    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 239
    Points
    4 239
    Par défaut
    Citation Envoyé par Tazze-99 Voir le message
    L'idée de parcourir les champs par 100 records me semble excellente mais je vois pas du tout comment la mettre en pratique. A moins d'arriver a faire comprendre à sql qu'il doit m'envoyer un certain morceau du résultat global. (de la ligne 100 as 150 par exemple) A ce moment la je peux générer un event sur la touche page down / page up qui lancerait un requête plus ciblé que le gros bazar que je lance actuellement.
    Solution a creuser

    Merci pour l'aide

    Cela par contre, ce n'est pas bien dur (à priori).
    Je n'ai pas fait attention à ta requête mais j'imagine qu'elle te renvoyé une manière d'identifier chaque ligne (une clef primaire quoi).

    Si oui, voici un bête exemple.

    Imaginons une table de client tout simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    TblClient
    Id Int (clef primaire)
    Nom varchar(50)
    Prenom varchar(50)
    Imaginons qu'elle contienne un million de record et qu'on veuille les afficher par bloc de 100. En admettant que la colonne Id ne contienne que des entiers positifs, au premier passage, on aura la requête suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    select top 100 * from TblClient where id > -1 order by id
    On affiche les données et on retient quel est le dernier id reçu.

    Quand on veut voir les 100 records suivant, il suffit de remplacer le -1 par le dernier id.
    Kropernic

  16. #16
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 154
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par griftou Voir le message
    Cela par contre, ce n'est pas bien dur (à priori).
    Je n'ai pas fait attention à ta requête mais j'imagine qu'elle te renvoyé une manière d'identifier chaque ligne (une clef primaire quoi).

    Si oui, voici un bête exemple.

    Imaginons une table de client tout simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    TblClient
    Id Int (clef primaire)
    Nom varchar(50)
    Prenom varchar(50)
    Imaginons qu'elle contienne un million de record et qu'on veuille les afficher par bloc de 100. En admettant que la colonne Id ne contienne que des entiers positifs, au premier passage, on aura la requête suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    select top 100 * from TblClient where id > -1 order by id
    On affiche les données et on retient quel est le dernier id reçu.

    Quand on veut voir les 100 records suivant, il suffit de remplacer le -1 par le dernier id.
    Mouif, sauf que si l'utilisateur décide de faire un tri par l'âge du capitaine et qu'il y a des doublons sur cette colonne, bah ça marche plus ton truc

    Il vaut donc mieux utiliser l'imbrication de TOP comme spécifié dans le lien que j'ai donné plus haut.
    On ne jouit bien que de ce qu’on partage.

  17. #17
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Points : 13 314
    Points
    13 314
    Par défaut
    Citation Envoyé par StringBuilder Voir le message
    Le LIMIT de MySQL n'existe pas avec SQL Server.
    Non, mais via les fonctions de fenetrage (RANK ... OVER ... PARTITION BY, etc ...) , on peut sans problème le simuler et sans contrainte de perf.

    Je ne réponds pas aux questions techniques par MP ! Le forum est là pour ça...


    Une réponse vous a aidé ? utiliser le bouton

    "L’ennui dans ce monde, c’est que les idiots sont sûrs d’eux et les gens sensés pleins de doutes". B. Russel

  18. #18
    Membre à l'essai
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Novembre 2011
    Messages : 13
    Points : 11
    Points
    11
    Par défaut
    Loin de moi l'idée de vouloir jouer les prétentieux et les casse-pieds mais vous êtes sur que l'exemple montré dans le lien de Stringbuilder est correcte ????

    J'ai modifié mon sql en suivant l'exemple du lien et je ne reçoit que les 10 premières lignes. J'ai modifié le 2ième top en 40 et là j'ai reçu les 30 premières lignes depuis la ligne 10.

    Je vais faire quelques tests pour voir le résultat.

  19. #19
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Points : 13 314
    Points
    13 314
    Par défaut
    Citation Envoyé par Tazze-99 Voir le message
    Loin de moi l'idée de vouloir jouer les prétentieux et les casse-pieds mais vous êtes sur que l'exemple montré dans le lien de Stringbuilder est correcte ????
    De toute manière ici c'est un cautère sur une jambe de bois.

    Le problème vient de ta requête et/ou de tes index.

    Commence par là, plutôt que d'essayer de dissimuler les mauvaises performances de l'accès aux données via l'affichage.

    Sinon, pour faire l'équivalent de "LIMIT" tu peux faire ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    select id from
    (select id, row_number() over (order by id desc)  as numLigne from theTable)
    where numLigne between 5 and 10
    (ici pour une seule colonne, sort les lignes entre la 5 et la 10).

    Je ne réponds pas aux questions techniques par MP ! Le forum est là pour ça...


    Une réponse vous a aidé ? utiliser le bouton

    "L’ennui dans ce monde, c’est que les idiots sont sûrs d’eux et les gens sensés pleins de doutes". B. Russel

  20. #20
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 154
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    C'est vrai que les fonctions de fenêtrage, c'est plus pratique que les TOP imbriqués

    Sinon, je ne suis que partiellement d'accord avec le fait que le problème vienne uniquement de la requête.

    Je suis certain que s'il lance sa requête dans un requêteur, il aura une réponse bien plus rapide que depuis son programme.

    Car je reste persuadé que le chargement dans un DataGridView est très lent, surtout si le volume de données est important.

    (et je ne parle pas si c'est un programme ASP.NET)
    On ne jouit bien que de ce qu’on partage.

Discussions similaires

  1. comment gérer en même temps input post et uri pour une recherche et pagination ?
    Par razily dans le forum Bibliothèques et frameworks
    Réponses: 0
    Dernier message: 22/03/2012, 14h24
  2. Problème requête sql pour une recherche
    Par Zoldik dans le forum Langage SQL
    Réponses: 21
    Dernier message: 03/03/2009, 14h01
  3. Syntaxe pour une recherche sur 2 listes déroutantes
    Par christ-94 dans le forum Access
    Réponses: 2
    Dernier message: 24/05/2006, 17h51
  4. Importance des accents pour une recherche dans postgre
    Par glouf dans le forum PostgreSQL
    Réponses: 4
    Dernier message: 05/03/2005, 13h25
  5. [VB.NET] Quel objet tableau pour une recherche indexée ???
    Par Kitano dans le forum Windows Forms
    Réponses: 7
    Dernier message: 02/09/2004, 09h38

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