2016-12-22 3 views
0
pend

J'ai une application de traitement par lots de la console qui comprend un processus qui utilise pour effectuer un SELECT simple sur une table SqlDataAdapter.Fill (DataTable).Fill (DataTable) réussit à l'essai, dans la production

private DataTable getMyTable(string conStr) 
    { 
     DataTable tb = new DataTable(); 
     StringBuilder bSql = new StringBuilder(); 
     bSql.AppendLine("SELECT * FROM MyDB.dbo.MyTable"); 
     bSql.AppendLine("WHERE LEN(IdString) > 0");     
     try 
     { 
      string connStr = ConfigurationManager.ConnectionStrings[conStr].ConnectionString; 
      using (SqlConnection conn = new SqlConnection(connStr)) 
      { 
       conn.Open(); 
       using (SqlDataAdapter adpt = new SqlDataAdapter(bSql.ToString(), conn)) 
       { 
        adpt.Fill(tb); 
       } 

      } 
      return tb; 
     }   
     catch (SqlException sx) 
     { 
      throw sx; 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 

Cette méthode est exécutée de façon synchrone, et a été exécuté avec succès dans plusieurs environnements de test sur plusieurs mois de tests - à la fois lors du démarrage de la ligne de commande ou commencé sous le contrôle d'un travail AutoSys.

En cas de déplacement dans la production, cependant, le processus accroché - à la méthode de remplissage autant que nous pouvons dire. Pire, au lieu de temporiser, il a apparemment commencé à engendrer de nouveaux threads de demande, et après quelques heures, avait consommé plus de 5 Go de mémoire sur le serveur d'application. Cela a affecté d'autres applications actives, ce qui m'a rendu très impopulaire. Aucune exception n'a été levée.

La chaîne de connexion est à peu près aussi simple que possible.

"data source=SERVER\INSTANCE;initial catalog=MyDB;integrated security=True;" 

Toutes mes excuses si j'utilise les mauvaises conditions en ce qui concerne ce que le DBA SQL indiqué ci-dessous, mais quand nous avions une trace mis sur le serveur SQL, il a montré l'ID d'application (en vertu de laquelle le travail AutoSys était en cours d'exécution) acceptées comme un login valide. Le serveur est ensuite apparu pour traiter la requête SELECT. Cependant, il n'a jamais retourné de réponse. Au lieu de cela, il est entré dans un statut de "commande en attente". Le fil de requête est resté ouvert pendant quelques minutes, puis a disparu.

Le DBA dit qu'il n'y avait aucun signe d'une impasse, mais qu'il aurait besoin de surveiller en temps réel pour déterminer s'il bloquait.

Cela se produit uniquement dans l'environnement de production; Dans les environnements de test, les serveurs SQL répondaient toujours en moins d'une seconde.

Le AutoSys ID d'application n'est pas un nouveau - il a été utilisé depuis plusieurs années avec d'autres serveurs SQL et n'a eu aucun problème. L'administrateur de base de données a même exécuté la requête SELECT manuellement sur le serveur SQL de production connecté en tant que cet ID, et il a répondu normalement.

Nous avons été incapables de reproduire le problème dans un environnement non-production, et hésiter à l'exécuter dans la production sans admin serveur debout pour tuer le processus. Nos exigences de sécurité limitent mon accès pour voir les journaux et les processus du serveur, et je dois généralement engager un autre spécialiste pour les regarder pour moi.

Nous devons résoudre ce problème tôt ou tard. La quantité de données que nous examinons n'est actuellement que de quelques lignes, mais augmentera au cours des prochains mois. De ce qui se passe, ma meilleure estimation est qu'elle implique la communication et/ou la sécurité entre le serveur d'application et le serveur SQL.

Toutes les idées ou éléments supplémentaires à étudier sont les bienvenus. Merci tout le monde.

+0

Avec les bases de données volumineuses, l'exécution de la requête dans VS peut prendre beaucoup de temps. Empêchez la pendaison J'utilise un BackGroundWorker pour faire du travail. Au lieu d'interroger la base de données directement, j'utilise cmd.exe qui est un exécutable en ligne de commande (livré avec SQL Server) pour effectuer une requête et produire un fichier csv avec des résultats. Ensuite, lisez les résultats dans l'application VS. Je lance cmd.exe à partir de C# en utilisant une classe de processus à l'intérieur d'un backgbroundworker. – jdweng

+0

@jdweng: Je pense que ce sont quelques bons points. s'il s'agit d'une simple instruction select, exécutez-la à partir de l'outil de ligne de commande sql, excluez la possibilité que quelque chose ne fonctionne pas dans l'application. Quelle est la taille de la table? Vous pouvez exécuter la sélection avec TOP 1000 pour vous assurer que les données de résultat sont comme prévu. Écrire des données à csv d'abord sembler étrange pour moi le premier moment, mais avec des données vraiment importantes, cela peut être un moyen. –

+0

Avec mon application, sqlcmd.exe prenait 30 minutes ou plus sur une base de données de 10 Go. Il prenait des heures comme une requête en C#. Et mes fenêtres pour l'application ont été suspendues pendant que la requête était en cours d'exécution. La seule méthode que j'ai trouvée pour obtenir les résultats de sqlcmd.exe dans C# était avec un fichier csv. – jdweng

Répondre

0

Bien qu'il puisse être causé par des permissions/ADO étranges.NET questions comme mentionné par @user1895086, je serais serait néanmoins recommander à revérifier quelques choses une fois de plus:

  1. Assurez-vous que les requêtes exécutées manuellement par DBA et exécutées dans votre App sont les mêmes - que ce soit ou codent en dur au moins Connectez-vous juste avant de courir. Il vaut mieux prévenir que guérir.
  2. Essayez de ne sélectionner que quelques lignes - c'est toujours une bonne idée de ne pas sélectionner la table entière si vous pouvez l'éviter, et dans notre cas SELECT TOP 1 (ou 100) requête peut ne pas présenter de tels problèmes. Peut-être qu'il y a juste beaucoup plus de données que vous ne le pensez et ADO.Net essaye consciencieusement de charger toutes ces lignes. Ou peut-être pas.
  3. Essayez SqlDataReader pour vous assurer que SqlDataAdapter ne pose aucun problème - oui, il utilise le même DataAdapter internally, mais nous exclurons au moins ces opérations supplémentaires d'une liste de suspects. Essayez de mettre la main sur la décharge avec ces 5 Go de mémoire - analyzing memory dumps n'est pas une tâche triviale, mais il ne sera pas trop difficile de comprendre ce qui mange ces gros morceaux de mémoire. Parce que je doute d'une manière ou d'une autre que ADO.NET va générer de nombreux objets supplémentaires sans raison.
+0

J'ai accepté cette réponse à cause de la suggestion de comparer la requête envoyée par l'application avec ce qui a été reçu par le serveur SQL. Il se produisait réellement dans une méthode exécutée après celle ci-dessus, et accédant à un DB différent avec Entity Framework. Une expression LINQ était censée amener EF à sélectionner au plus quelques centaines de lignes. Au lieu de cela, la requête qu'il a convertie à partir de LINQ essayait de charger une table entière de 1,7 million de lignes en mémoire, ET de le faire sur 3 threads de requête distincts. – 66AndStillLearning

1

Ceci peut être lié à des permissions. SQL Server fait des choses étranges au lieu de donner parfois un message d'erreur approprié.

Ma suggestion, et cela pourrait améliorer les performances de toute façon, est d'écrire une procédure stockée sur le côté serveur qui exécute la sélection et appeler la procédure stockée. De cette façon, l'administrateur de base de données peut s'assurer que vous avez un accès correct à la procédure stockée sans permettre un accès direct à la table si, pour une raison quelconque, il est bloqué, et que vous devriez voir une légère amélioration des performances.

+1

Alors que je suis d'accord avec presque tout ici pourquoi pensez-vous qu'une procédure stockée va offrir une amélioration des performances sur une requête ad hoc? –

+0

Cela entre dans un débat qui fait rage entre les programmeurs et depuis un certain temps, surtout maintenant que la fenêtre est rétrécie. Il y a eu une époque où cela faisait une différence beaucoup plus grande, mais maintenant c'est plus basé sur l'environnement. Cependant, l'utilisation de procédures stockées améliore très légèrement les performances (car cela semble donner plus de liberté au SGBD pour optimiser la requête.) Pourquoi? Je ne suis pas un administrateur de base de données) tout en évitant certains pièges qui peuvent survenir lors d'une utilisation ad hoc. il permet également de modifier les paramètres de votre requête sans avoir à recompiler le code et à le redéployer aux consommateurs. – CDove

+0

Il n'augmente pas les performances. Une exécution est compilée et mise en cache pour une requête ad hoc identique à une procédure stockée depuis sql 6.5 (il y a près de deux décennies). Je ne dis pas que je préfère les requêtes ad hoc aux procédures stockées. Au contraire, je suis tout à fait favorable aux procédures stockées et je n'écrirais jamais ma propre requête ad hoc, pour la plupart des raisons que vous venez de mentionner. Cependant, il est long fallacy qu'une procédure stockée est plus rapide qu'une requête ad hoc. Ce n'est simplement pas vrai. Consultez cet article sur les procédures stockées. https://sqlperformance.com/2013/05/t-sql-queries/another-argument-for-stored-procedures. –