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

ADO.NET Discussion :

Import de données dans plusieurs tables


Sujet :

ADO.NET

  1. #1
    Membre du Club
    Profil pro
    Développeur Web
    Inscrit en
    Mai 2007
    Messages
    67
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 67
    Points : 48
    Points
    48
    Par défaut Import de données dans plusieurs tables
    Bonjour à tous,

    Je travaille actuellement sur une application d'e-commerce. L'environnement est le framework .Net 2.0 couplé à une base en SQL server. Nous n'utilisons pas les procédures stockées ().

    Chaque jour/semaine, notre client (le propriétaire du magasin) me donne un certain nombre de fichiers excel, dont je dois me servir pour mettre la base à jour (modifier les produits/clients/etc. modifiés et ajouter les nouveaux par exemple). Donc j'ai commencé à développer un service qui va chaque jour récupérer ces données, et dans un premier temps les importer dans des objets 'DataTable' (qui ne correspondent donc pas encore aux tables de la base de données). L'étape suivante, c'est de vérifier si ces données sont conformes (notre client étant un peu laxiste). J'en suis à peu près à là.

    Comment procéder, en SQL ou en .Net, à la mise à jour de la base à partir de ces données locales ?

    Je vois plusieurs méthodes. Mais soit elles ne me conviennent pas :
    1- Effectuer une boucle pour chaque produit, vérifier dans la base s'il existe, si oui le mettre à jour (UPDATE), sinon l'insérer (INSERT). Selon moi c'est une mauvaise méthode, trop de requêtes SQL sont générées.
    2- Récupérer en local l'intégralité des tables à modifier (loadDataSet), effectuer les modifications en local pour chaque produit à importer (modification ou ajout d'une DataRow), et appeler pour chaque table en fin de traitement un UpdateDataSet qui va effectuer les mises à jour. Selon moi, ce n'est pas une solution viable si les données sont trop nombreuses en base, et ça reste coûteux en temps.

    Soit je ne sais pas comment les réaliser :
    A- Récupérer en local uniquement les lignes qui vont être mises à jour (mais je ne sais même pas comment passer une liste d'id à ma requête pour qu'elle ne me retourne que ceux-là ) et effectuer le traitement en local comme dans la solution 2
    B- Copier les données dans la base (table temporaire ou autre), et traitement dans la foulée effectué par un update/insert (suivant les cas...) en masse de ces données.

    Auriez-vous une idée ? Ou une autre suggestion ?

  2. #2
    Membre chevronné
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 1 048
    Points : 2 201
    Points
    2 201
    Par défaut
    Sous quel forme va être l'application s'occupant de cette mise à jour. (client lourd windows, page web, service windows)

    Quel est la fréquence et le moment de ces mises à jour?

    Ensuite tu parles de solution pas idéale à ton gout car trop de requête (à savoir c'est pas parce qu'on a une instruction .net pour mettre un jour un dataset que les techno derrière vont faire une requête sql hein...), mais as-tu déjà mesuré la charge réel des requêtes et des procédures (Es-tu sur de pas te poser des questions qui n'ont pas lieu d'être)?

    A savoir que le chargement de ta base de donnée dans un dataset (en local), ne doit à priori pas "bloquer" ton site web (pas de calcul sur requête, pas de lock sur les enregistrement), mais peut poser des problèmes au niveau de l'application client (bien que je doute que la taille des tables en question soit critique à ce point). L'update peut être plus problèmatique (surtout avec des transaction) mais bon ce qui doit être mis à jour doit être mis à jour donc la solution est plutot une planification de l'opération pendant les heures creuses du site. Pour autant que cette dernière ait vraiment un impact sur les performance et la disponibilité du site (ce qui doit être un fait et non une supposition)

  3. #3
    Rédacteur
    Avatar de The_badger_man
    Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2005
    Messages
    2 745
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 745
    Points : 8 538
    Points
    8 538
    Par défaut
    SQL server (depuis 2005) intègre un outil dédié à ce genre de scénario: SSIS.

  4. #4
    Membre du Club
    Profil pro
    Développeur Web
    Inscrit en
    Mai 2007
    Messages
    67
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 67
    Points : 48
    Points
    48
    Par défaut
    Mince, je pensais avoir activé le suivi sur ce thread...
    Sous quel forme va être l'application s'occupant de cette mise à jour. (client lourd windows, page web, service windows)
    Il s'agit d'une dll ajoutée au programme Autorun, qui est un planificateur de tâche qui peut fonctionner en mode "service windows" comme en mode client lourd (mais ici c'est le mode service qui est utilisé).
    Quel est la fréquence et le moment de ces mises à jour?
    Quotidienne.
    L'update peut être plus problèmatique (surtout avec des transaction) mais bon ce qui doit être mis à jour doit être mis à jour
    Ma question porte justement sur le "comment" faire cette mise à jour en minimisant :
    - Le nombre de requêtes envoyées à la base (++)
    - Le temps de traitement / la quantité de mémoire utilisée en local (+)
    Après test, quand j'utilise la méthode de charger ma base en local, ce qui prend du temps ce sont les vérifications sur ces données en local - tous les DataView.SortFilter = "<critere>" ou DataTable.Select("<critere>") - (jusqu'à 5 ou 6 minutes pour un fichier test contenant 3000 clients... j'imagine la charge quand on passe aux produits, avec plusieurs dizaines de milliers d'articles et non pas une mais 6 ou 7 tables à impacter).
    L'autre problème que je vois venir c'est la consommation mémoire, 100 000 articles chargés, chacun pesant une ou deux images, une description, etc., ça risque de vite grimper.
    Et je n'ai pas pu mesurer la charge sur la BDD, je n'ai pas de jeu de données suffisamment grand pour mesurer quelque chose de significatif pour l'instant. Mais peut-être que ce n'est pas un problème tu as raison !

    SQL server (depuis 2005) intègre un outil dédié à ce genre de scénario: SSIS.
    Je doute avoir le temps de passer sur cette solution, mais un grand merci quand-même, la prochaine fois je regarderai ça en priorité : ça a l'air tout à fait puissant !

    Pour l'instant je me suis rabattu sur une méthode simple, on charge les données à mettre à jour en local depuis les fichiers du client sous la forme d'une table, puis pour chaque ligne de cette table on effectue l'Insert / l'Update qui va bien (la 1ère méthode que je décrivais en post 1). Ça me permet de loguer les erreurs au cas par cas et de faire un retour correct au client, mais j'ai des doutes sur les performances.

  5. #5
    Membre chevronné
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 1 048
    Points : 2 201
    Points
    2 201
    Par défaut
    Et la machine executant ce service se situe, d'un point de vue réseau, "à proximité" de la base de donnée à traiter ? (Même machine,Y a une ligne réseau 100mb, voir 1Gb ou c'est un poste à l'autre bout du monde en RTC).

    En tout cas 5 minutes pour faire un select sur dataset avec 3'000 fiches clients. Il y a un problèmes quelque part (même 5 secondes ça me semble trop). Pour charger le dataset selon les conditions réseaux je veux bien mais à l'utilisation...

    Je ne peux que te donner les conseils suivants:

    - L'application (ou service) doit s'executer si possible en tâche planifiée (genre à minuit, à voir avec d'autres tâches planifiées) sur un serveur, proche (ayant un bon débit) avec la base de donnée, idéalement sur la même machine.

    - Charger uniquement dans le dataset ce qui est utile, c'est à dire les tables et les colonnes susceptible d'être modifiée (Et ensuite si ça représente toujours trop alors on limite au niveau des enregistrements). Inutile de charger l'historique des clients si c'est juste pour changer le nom de ce dernier!

    - Viser en premier lieu un algo qui fonctionne avant de chercher à faire un algo qui va vite. Ce n'est, en principe, pas critique que ton script mette 20 minutes à traiter les données à 1h00 du matin (surtout si les opération d'update prennent seulement 20 secondes...). On rigole mais entre présenter un truc au client qui ne marche pas ou un truc qui marche "lentement" (c'est un aspect très subjectif), on comprend vite dans quel situation on a l'air le moins con...

    - Si tes photos sont en binaire dans ta base de donnée, ben tu ne feras pas la même erreur la prochaine fois

  6. #6
    Membre du Club
    Profil pro
    Développeur Web
    Inscrit en
    Mai 2007
    Messages
    67
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 67
    Points : 48
    Points
    48
    Par défaut
    La base et mon service doivent pouvoir fonctionner indifféremment en local ou via une ligne internet quelconque (mettons 100 Mb).

    En tout cas 5 minutes pour faire un select sur dataset avec 3'000 fiches clients. Il y a un problèmes quelque part (même 5 secondes ça me semble trop). Pour charger le dataset selon les conditions réseaux je veux bien mais à l'utilisation...
    Je me suis mal exprimé alors. Ça prend 5 minutes quand je suis ces étapes :
    - Je charge les fichiers du client (données à intégrer à la base) en local (DataTable) : temps assez court
    - Je charge les tables à impacter de la base de données en local (DataSet) : temps assez court
    - Je parcours chaque ligne du fichier client (3000 lignes) et pour chaque ligne je dois vérifier sur les DataSet s'il existe déjà (donc un select par ligne client = 3000 select si on a une seule table où chercher les id, et beaucoup plus quand on doit chercher dans d'autres tables des informations que le client n'a pas données, par exemple l'id du code postal dans la base, etc.) : 5 à 6 minutes

    - Charger uniquement dans le dataset ce qui est utile, c'est à dire les tables et les colonnes susceptible d'être modifiée (Et ensuite si ça représente toujours trop alors on limite au niveau des enregistrements). Inutile de charger l'historique des clients si c'est juste pour changer le nom de ce dernier!
    Oui, pour le filtre sur les tables et les colonnes c'est OK. Je me demandais s'il n'était pas possible de filtrer sur les lignes (je m'explique) :
    - On récupère la liste des id des clients du fichier client
    - Quand on récupère en local les données de la base, on précise une close WHERE où on spécifie ces id : WHERE Client.id IN (<ma_liste_d_id>)
    Mais je n'ai trouvé qu'une méthode spécifique SQL server pour faire ça proprement (i.e. passer par un paramètre) mais sans procédure stockée et sans recopiage de table dans la base. Je dois pouvoir faire évoluer ma solution vers une autre base.

    - Si tes photos sont en binaire dans ta base de donnée, ben tu ne feras pas la même erreur la prochaine fois
    Tu suggères de ne stocker que des liens ? Ça peut encore se faire je pense.



    Autre chose, charger les données en local me pose un autre souci :
    - Mettons que je veuille traiter complètement chaque client avant de passer au suivant (par exemple pour le faire dans une transaction par client), et que les informations de chaque client se trouvent dans plusieurs tables ;
    - Mes données sont chargées dans un dataset (ou un dataset par table, suivant ce qui est le plus pratique - à vous de me dire pour le coup si ça change qqch) ;
    - Comment je procède ? Quand j'appelle la méthode Update de mon dataadapter, il va mettre à jour table par table puis client par client, et pas l'inverse... ce qui est problématique (ça m'impose de mettre le commit de la transaction à la fin de la maj de chaque table, mais pas de chaque client).

  7. #7
    Membre chevronné
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 1 048
    Points : 2 201
    Points
    2 201
    Par défaut
    Concernant le chargement par ligne:

    Il faut savoir que le tableAdapter n'est pas objet magique (enfin si un peu quand même) mais qu'il génére des instructions SQL, utilise des datareader pour executer des requêtes sur la base et fait des addrow sur les datatables pour les remplir.

    Rien ne t'empêche de mettre ton grain de sable dans la routine afin qu'elle colle mieux à ton besoin (Remplir le dataset à la main, Faire une nouvelle méthode de fill sur le tableAdapter). Une boucle sur un fillById ajoutant uniquement un client peut être une idée (Pas dit que tu perds en perf). (C'est possible de passer des paramètres au dataAdapter afin qu'il les transcrive directement dans le texte de la requête).

    Concernant les photos, je conseille de sauvegarder que les liens. D'autant plus que sur ton application web au final tu génères une page HTML et que les images en HTML c'est des liens... (On evite aussi de faire exploser la taille de la base de donnée et de ces backups). Sauvegarder des binaires dans une base de données c'est faisable, mais ça risque de te traumatiser (après faut voir la techno de la base de donnée aussi).

    Concernant les transactions. Elle ne doivent être utiles que si un lot d'instruction doit être effectué uniquement dans son entier (Exemple produit de remplacement: 1er Instruction - Ajout Produit, 2ème instruction remplacement produit dans les paniers, 3ème instruction Détruit le vieux produit). L'objet TableAdapter ne gère pas en natif les transaction (le tableadaptermanager et son updateAll utilise une transaction par contre). Il est possible d'ajouter le support de la transaction au TableAdapter avec les classe partielle (recherche google pour la soluce).

    Ensuite tu peux traiter un client sur plusieurs tables, faire une update de ces tables avec une transaction commune et recommencer pour le client suivant ou traiter tout les clients sur toutes les tables et updater ensuite le tout(à toi de voir ce qui te correspond le mieux à la demande...)

  8. #8
    Membre du Club
    Profil pro
    Développeur Web
    Inscrit en
    Mai 2007
    Messages
    67
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 67
    Points : 48
    Points
    48
    Par défaut
    Une boucle sur un fillById ajoutant uniquement un client peut être une idée (Pas dit que tu perds en perf).
    Pas bête...

    Concernant les photos, je conseille de sauvegarder que les liens. D'autant plus que sur ton application web au final tu génères une page HTML et que les images en HTML c'est des liens...
    Oui mais en fait non, il y a tout un tas d'outils qui scannent la base et qui s'attendent à voir des images en binaire pour les dupliquer sur les serveurs des sites web justement (réplication de données), et je ne peux pas toucher à ça.

    L'objet TableAdapter ne gère pas en natif les transaction (le tableadaptermanager et son updateAll utilise une transaction par contre). Il est possible d'ajouter le support de la transaction au TableAdapter avec les classe partielle
    Je n'utilise pas les TableAdapter (et encore moins les TableAdapterManager, étant sous VS2005), la BDD est sous SQL server 2008 et n'est pas gérée par VS2005... Du moins je crois que c'est bloquant pour ça.

    Ensuite tu peux traiter un client sur plusieurs tables, faire une update de ces tables avec une transaction commune et recommencer pour le client suivant ou traiter tout les clients sur toutes les tables et updater ensuite le tout(à toi de voir ce qui te correspond le mieux à la demande...)
    Oui je regarde ça, du coup j'ai repris un bout d'existant qui utilise la 1ère méthode.

Discussions similaires

  1. Importer des données dans plusieurs tables
    Par SylvainM dans le forum Requêtes et SQL.
    Réponses: 4
    Dernier message: 12/11/2008, 19h53
  2. Réponses: 4
    Dernier message: 06/01/2007, 21h51
  3. Réponses: 19
    Dernier message: 28/07/2006, 10h57
  4. Réponses: 7
    Dernier message: 12/10/2004, 16h43
  5. Réponses: 6
    Dernier message: 15/04/2004, 11h04

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