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 :

Multithreading et INSERT


Sujet :

VB.NET

  1. #1
    Membre confirmé
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Par défaut Multithreading et INSERT
    Bonjour à tous,

    J'espère poster dans la bonne section. Voici mon problème. Je développe actuellement un programme de récupération des emails avec insertion dans une base de données PostgreSQL. J'utilise le multithreading pour pouvoir améliorer les performances, et extraire les message de plusieurs utilisateurs en même temps.
    Mon soucis et qu'il m'arrive d'avoir une incohérence dans ma base de données du fait du multithreading. Par exemple, j'ai dans ma table 60 messages, il arrive parfois qu'a la même seconde, mes 2 threads font une requete pour compter le nombre de messages dans la table avant insertion, et du coup, insère le même n°ID dans ma table

    J'espère que je suis assez claire dans ma description, car c'est vraiment un phénomène bizarre que je n'arrive pas à comprendre.

    Avez vous une théorie pour contrer ce problème ?

    Merci à tous.

  2. #2
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Ne pourrais-tu pas simplement utiliser une colonne auto-incrémentée pour l'ID ?

    Sinon, puisque ta DB ne semble être pilotée que par une unique copie de ton application, plutôt que d'utiliser une requête du nombre de lignes pour déterminer le nouvel ID, tu pourrais simplement maintenir un champ que tu mettrais à jour via la classe Interlocked ou des verrous.

  3. #3
    Membre confirmé
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Par défaut
    Merci pour ta réponse.

    Si je ne confond pas, les verrous sont mis en place par des transactions c'est bien ça ? Si c'est le cas, je dois voir si c'est faisable avec mon ODBC vers Postgresql... pourrais tu m'en dire un peu plus sur ces verrous ou une classe Interlocked ?

    Merci beaucoup.

  4. #4
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Bonjour.

    Non, pas ces verrous-là. Je pensais aux primitives de synchronisation dotnet (les instructions "lock", les classes Monitor, Interlocked). Aucun rapport les mécanismes de concurrence des DB. Encore une fois, ceci ne serait valable que si ta DB n'est consommée que par une seule copie d'une seule application mais, si c'est le cas, ce serait le plus efficace.

    Si ce n'est pas le cas et qu'un champ autoincrémenté n'est pas possible, le plus simple est de retenter la transaction jusqu'à ce que ça passe (concurrence optimiste, idéal quand tu as peu d'accès simultanés).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    while(true)
    {
        int id = NbLignes() + 1;
        if (EssayerInsertion(id) == "success") break;
    }
    Tu peux aussi tenter une requête imbriquée, avec "VALUES((SELECT COUNT(*) FROM matable), 'dupont', 'jean')" mais je ne crois pas que ça fonctionne.

  5. #5
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 204
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    Par défaut
    le mieux reste le champ auto incrément sinon :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    insert into table (ch1, ch2) values ((select max(ch1) +1 from table), vCh2)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  6. #6
    Membre confirmé
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Par défaut
    Merci pour ces informations.

    Malheureusement, le champ autoincrémenté n'est pas possible et la DB n'est pas consommée que par une seule copie d'une seule application.

    En général, l'insertion passe toujours, mais mon problème se situe au niveau du multithreads. C'est a dire que 2 threads insère une ligne en même temps, et comme je fais un SELECT COUNT(*) juste avant pour récupérer le nombre d'éléments dans ma table, les 2 threads insérent le même id en même temps...

    Je vais essayer de gérer ça par des transactions ou avec BULK, peut être que c'est une possibilité.

  7. #7
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 204
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    Par défaut
    la solution que je donne a des chances d'être bonne

    et le salect max est mieux que le select count en théorie, car s'il y a des suppression, le count va créer des doublons ...

    après il y a aussi l'index unique qui empêchera les doublons et génèrera une erreur, auquel cas tu peux retenter dans la foulée
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  8. #8
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Pourquoi ne peux-tu pas ajouter de colonne auto-incrémentée (serial je crois avec postgresql) ? Tu ne peux pas modifier les tables existantes ?

    Sinon, tu n'as pas de contrainte d'identité sur ta colonne ID ? Si tu en ajoutes une, l'insertion échouera en cas de doublon, ce qui rend possible la solution que j'avais proposé en code. Où est-ce que là aussi c'est un problème de schémas intouchables ?

  9. #9
    Membre confirmé
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Par défaut
    Oui, je ne sais pas pourquoi j'ai pas mis une colonne autoincrémenté, mais il me semble que ce n'était pas compatible. je vais refaire un test pour voir car la j'ai un doute. Mais est-ce que le probleme sera résolu avec un auto incrément ? J'entend par la, si les 2 threads font un insert en même temps (au centième de seconde près), ça donnera quoi ?

  10. #10
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 204
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    Par défaut
    oui, l'auto incrément est géré par la base elle même donc aucun soucis possible même avec 15millions d'insert sur 15millions de threads simultannés ^^
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  11. #11
    Membre confirmé
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Par défaut
    Cool Je teste ça et vous tiens au courant !

    Merci

  12. #12
    Membre confirmé
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Par défaut
    Bon, alors voilà pourquoi la serial n'est pas possible (je pense)
    En effet, l'id de la table n°1 doit aussi etre inséré dans une table n°2.
    Par exmple, si 2 utilisateurs possèdent le même message (déja présent dans la table n°1), alors dans ce cas je n'insère pas dans la table n°1 mais je fais référence à ce message vers la table n°2

    Donc si je met un serial, je ne pourrais plus inséré cet id dans ma table n°2, à moins qu'il existe une solution que j'ignore ?

    Merci

  13. #13
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 204
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    Par défaut
    Citation Envoyé par wmenant Voir le message
    à moins qu'il existe une solution que j'ignore ?
    c'est surement le cas !

    je ne connais pas PostgreSQL mais ca n'a pas mauvaise réputation comme un mysql, donc il doit y avoir ce qu'il faut, à savoir une instruction pour connaitre l'auto incrément généré (et donc le réutiliser sous forme de variable pour la suite)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  14. #14
    Membre confirmé
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Par défaut
    Très juste !

    select currval('table_id_column_seq');
    Donc avec ça, je peux récupérer mon ID auto incrémenté et l'inséré dans ma table n°2 ! je test ça et vous tiens au courant ^^


  15. #15
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 204
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    Par défaut
    vu le nom, je pense qu'il y a mieux

    sur sql server on plusieurs instructions pour faire ca, genre une qui dit la valeur actuelle, et une qui dit la dernière valeur générée par la connexion actuelle ... si tu vois où je veux en venir ...
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  16. #16
    Membre confirmé
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Par défaut
    Surement à SELECT @@IDENTITY

    en fait sous postgresql, la solution apparement c'est :

    INSERT mytable(myid) VALUES (nextval('MySequence'));

    SELECT currval('MySequence');

    currval works like @@identity and will return the current value of the sequence in the same session.

    http://database.sarang.net/database/...de74.html#5906

Discussions similaires

  1. STL list insertion Multithreading
    Par pavel dans le forum C++
    Réponses: 2
    Dernier message: 17/03/2010, 15h00
  2. probleme d'insertion d'un Float
    Par neness dans le forum Débuter
    Réponses: 3
    Dernier message: 07/01/2003, 13h32
  3. [Postgresql] pb lors d'insertion de données
    Par bob20000 dans le forum Requêtes
    Réponses: 8
    Dernier message: 04/11/2002, 16h33
  4. Multithreading sous HP Ux 11
    Par pykoon dans le forum Autres éditeurs
    Réponses: 1
    Dernier message: 19/10/2002, 00h36
  5. Réponses: 4
    Dernier message: 28/09/2002, 01h00

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