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

C# Discussion :

Avancement d'un script SQL


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Modérateur
    Avatar de sevyc64
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2007
    Messages
    10 251
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 251
    Par défaut Avancement d'un script SQL
    Salut à tous.

    Dans le cadre du développement d'un outil de grosse maintenance ponctuelle de bases de données client, j'ai un script SQL (SQLServer 2017) que j'appelle depuis un code C# :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
                using (SqlConnection cnx = CommonTools.GetSqlConnection(databaseNameCible))
                {
                    string scriptFilePath = System.IO.Path.Combine(Environment.CurrentDirectory, "SqlScripts", "mon_script.sql");
                    string sqlScript = System.IO.File.ReadAllText(scriptFilePath);
                    using (SqlCommand cmd = new SqlCommand(sqlScript, cnx))
                    {
    					cmd.Parameters.Add("@BddCible", SqlDbType.VarChar);
    					cmd.Parameters["@BddCible"].Value = databaseNameCible;
    					cmd.Parameters.........
     
    					cnx.Open();
    					cmd.ExecuteNonQuery();
                    }
                }
    Ce script contient plus de 300 requêtes encadrées par une transaction (elle est gérée directement dans le script pour le moment, mais si nécessaire, je devrais pouvoir la déplacer dans le C# au besoin). Sur de très grosses bases il peut prendre plusieurs 10ènes de minutes à s'exécuter entièrement.
    NOTA : Je suis pour le moment sur du code synchrone, mais je m'interdis pas de passer sur de l'async/await, voire explicitement des task si besoin.

    Afin de faire patienter l'utilisateur et éventuellement alimenter un log, je souhaiterais que ce script puisse me renvoyer régulièrement une information d'avancement.
    - Existe-il des instructions à rajouter dans le script sql pour qu'il renvoie régulière, mais immédiatement, pas à la fin de l'exécution, une information pouvant indiquer l'avancement
    - comment, coté code C# récupérer cette info (callback, peut-être ?), en temps réel, et non pas uniquement une fois que ExecuteNonQuery rend la main.

    Est-ce simplement possible ?



    Bon, j'ai toujours une solution un peu barbare, qui serait de découper automatiquement le script et de ne l'exécuter que par blocs de 10% des lignes, en prenant garde à avoir 1 requête=1ligne. Mais je trouve pas ça très "pro", c'est un peu bricole

  2. #2
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 972
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 972
    Par défaut
    Le script SQL va s'exécuter d'un bout à l'autre sans notifier l'appelant.
    Si tu veux que ton IHM soit au courant de l'avancement, tu n'a d'autre choix que d'utiliser une mécanique indépendante de ton script mais que ton script pourra appeler au besoin.

    La première idée qui me viens à l'esprit est de créer une table temporaire servant à décrire l'avancement d'une tâche.
    Ton script alimenterai régulièrement cette table temporaire.
    Et ton application C# pourrai la lire à intervalle régulier pour notifier au niveau de l'IHM.

  3. #3
    Modérateur
    Avatar de sevyc64
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2007
    Messages
    10 251
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 251
    Par défaut
    C'est une piste effectivement.


    Par contre, il me semblait bien que j’avais déjà mis en place un tel mécanisme. Je viens de retrouver le code. Mais c'était sur les 2 instructions particulière BACKUP et RESTORE, en utilisant ce bout de code (en vb celui-ci)
    Code vb : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
                   Using Command = New SqlCommand("RESTORE DATABASE [" + databaseName + "] FROM DISK='" + filePath + "' WITH REPLACE, STATS = 1", connection)
                        connection.FireInfoMessageEventOnUserErrors = True
                        AddHandler connection.InfoMessage, AddressOf InfoMessageHandler
                        Command.CommandTimeout = dureeTrait
     
                        ' L'option FireInfoMessageEventOnUserErrors transforme les exceptions concernant les backups en simple message d'information
                        ' Il faut donc les filtrer, s'ils apparaissent, pour recréer manuellement une exception
                        ProcessAsyncError = String.Empty
                        Await Command.ExecuteNonQueryAsync()
                        RemoveHandler connection.InfoMessage, AddressOf InfoMessageHandler
                    End Using

    Je sais pas si ça marcherait dans mon cas, il va falloir que je fasse quelques tests demain, pour voir ce que je récupère.

  4. #4
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 972
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 972
    Par défaut
    SqlDataReader n'est pas adapté puisqu'il s'agit de notifier de l'avancement d'un script complet.

  5. #5
    Modérateur
    Avatar de sevyc64
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2007
    Messages
    10 251
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 251
    Par défaut
    effectivement mon script ne renvoie pas de données, c'est une collection de requêtes update, delete et insert.

  6. #6
    Expert confirmé
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 537
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 537
    Par défaut
    Citation Envoyé par sevyc64 Voir le message
    effectivement mon script ne renvoie pas de données, c'est une collection de requêtes update, delete et insert.
    et en mettant des compteurs dans le script SQL retournés à chaque exécution de requête c'est pas une solution ?
    Sinon en faisant des Insert Delete en C# donc en déplaçant le script évidemment cela résoudra le problème.
    Par contre le code va s'exécuter côté programme et non SGBDR.
    Bref faut voir

  7. #7
    Expert confirmé

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 761
    Billets dans le blog
    21
    Par défaut
    Bonjour,

    Je pense que ce que tu recherches peut se faire via l'événement SqlConnection.InfoMessage.

    En gros, dans ton script SQL, tu peux simplement mettre des PRINT 'Processing... 5%' par exemple. Les PRINT devraient déclencher l'événement InfoMessage. Il te suffit donc de parser le message dans cet événement pour avoir l'état d'avancement.

    C'est moins lourd que de passer par une table temporaire, et fonctionne également dans le cas où plusieurs requêtes simultanées (via des connexions différentes bien sûr) s'exécutent.

    [EDIT]
    alternative au PRINT : utiliser un SET COUNT ON SET NOCOUNT OFFdans le script SQL. Ainsi, à chaque fois qu'il y a une exécution d'une instruction, tu as une ligne du style "xxx lignes affectées". Si le nombre d'instruction INSERT/SELECT/UPDATE/DELETE est fixe (pas de boucle ni de conditionnel côté SQL), alors tu peux exécuter une fois le script afin de déterminer le nombre de ligne. Puis, lors des exécutions suivantes, tu comptes le nombre de ligne "xxx lignes affectées" pour savoir où tu en es exactement...

    Après, dans un cas comme dans l'autre, l'hypothèse pour que cela fonctionne correctement, c'est que dans ton script, la durée d'exécution soit répartie sur l'ensemble des requêtes, et qu'il n'y ait pas une requête qui à elle seule corresponde à 99% du temps d'exécution de ton script...

    [EDIT2]
    Dans le EDIT, j'ai modifié le SET COUNT ON en SET NOCOUNT OFF. S'ils sont sémantiquement équivalent, le premier n'existe... pas

Discussions similaires

  1. Execution d'un script SQL
    Par Drahu dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 05/03/2004, 16h55
  2. Génération de script SQL avec les données
    Par borgfabr dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 05/03/2004, 13h57
  3. Exécuter un script SQL
    Par borgfabr dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 05/03/2004, 08h47
  4. create user, affectation droits et scripts sql
    Par hirochirak dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 03/02/2004, 10h21
  5. script SQL : affectation de variables
    Par Laura dans le forum Requêtes
    Réponses: 3
    Dernier message: 28/10/2003, 21h32

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