Je suis tombé sur du code développeur où la méthode SqlCommand.Prepare () (voir MSDN) est largement utilisée avant l'exécution des requêtes SQL. Et je me demande quel est l'avantage de cela?
Échantillon:
command.Prepare();
command.ExecuteNonQuery();
//...
command.Parameters[0].Value = 20;
command.ExecuteNonQuery();
J'ai joué un peu et tracé. L'exécution de la commande après l'appel de la Prepare()
méthode oblige Sql Server à exécuter l'instruction suivante:
declare @p1 int
set @p1=1
exec sp_prepexec @p1 output,N'@id int,@desc text',N'INSERT INTO dbo.testtable (id) VALUES (@id)',@id=20'
select @p1
Après cela, lorsque le paramètre obtient sa valeur et SqlCommand.ExecuteNonQuery()
est appelé, ce qui suit est exécuté sur Sql-Server:
exec sp_execute 1,@id=20
Pour moi, cela ressemble à la déclaration qui est en quelque sorte compilée dès qu'elle Prepare()
est exécutée. Je me demande quel est l'avantage de cela? Cela signifie-t-il qu'il est placé dans le cache du plan et peut être réutilisé dès que la requête finale est exécutée avec les valeurs de paramètre souhaitées?
J'ai compris (et documenté cela dans une autre question ) que les commandes SqlCommands qui sont exécutées avec SqlParameters sont toujours enveloppées dans sp_executesql
des appels de procédure. Cela rend Sql Server capable de stocker et de réutiliser les plans indépendamment des valeurs des paramètres.
À ce sujet, je me demande si la prepare()
méthode est un peu inutile ou obsolète ou si je manque quelque chose ici?
Réponses:
La préparation d'un lot SQL séparément de l'exécution du lot SQL préparé est une construction qui est effectivement **inutile pour SQL Server étant donné la façon dont les plans d'exécution sont mis en cache. Séparer les étapes de préparation (analyse, liaison des paramètres et compilation) et d'exécution n'a de sens que lorsqu'il n'y a pas de mise en cache. Le but est de gagner du temps sur l'analyse et la compilation en réutilisant un plan existant, et c'est ce que fait le cache du plan interne. Mais tous les SGBDR ne font pas ce niveau de mise en cache (clairement à cause de l'existence de ces fonctions) et il est donc laissé au code client de demander qu'un plan soit "mis en cache", et donc de sauvegarder cet ID de cache, puis de réutiliser il. C'est une charge supplémentaire sur le code client (et le programmeur de se rappeler de le faire et de bien faire les choses) qui n'est pas nécessaire. En fait, la page MSDN de la méthode IDbCommand.Prepare () indique:
Il convient de noter que, pour autant que mes tests le montrent (ce qui correspond à ce que vous montrez dans la question), appeler SqlCommand.Prepare () , ne fait pas une opération de "préparation" uniquement: il appelle sp_prepexec qui prépare et exécute le SQL ; il n'appelle pas sp_prepare qui est uniquement d'analyse et de compilation (et n'accepte aucune valeur de paramètre, uniquement leurs noms et types de données). Par conséquent, il ne peut y avoir aucun avantage de «précompilation» de l'appel
SqlCommand.Prepare
car il effectue une exécution immédiate (en supposant que le but est de différer l'exécution). CEPENDANT , il y a un avantage mineur potentiel intéressant d'appelerSqlCommand.Prepare()
, même s'il appellesp_prepexec
au lieu desp_prepare
. Veuillez consulter la note (** ) en bas pour plus de détails.Mes tests montrent que même lorsque l'
SqlCommand.Prepare()
on appelle (et veuillez noter que cet appel ne pas émettre de commandes sur SQL Server), leExecuteNonQuery
ouExecuteReader
qui suit est entièrement exécutée, et si elle est ExecuteReader, il renvoie des lignes. Néanmoins, SQL Server Profiler montre que le premierSqlCommand.Execute______()
appel après l'SqlCommand.Prepare()
appel est enregistré en tant qu'événement «Préparer SQL» et que les.Execute___()
appels suivants s'enregistrent en tant qu'événements «Exec Prepared SQL».Code de test
Il a été téléchargé sur PasteBin à: http://pastebin.com/Yc2Tfvup . Le code crée une application console .NET / C # qui est destinée à être exécutée pendant l'exécution d'une trace SQL Server Profiler (ou une session d'événements étendus). Il marque une pause après chaque étape afin de savoir clairement quelles instructions ont un effet particulier.
MISE À JOUR
Trouvé plus d'informations et une légère raison potentielle pour éviter d'appeler
SqlCommand.Prepare()
. Une chose que j'ai remarquée lors de mes tests, et ce qu'il convient de noter pour quiconque exécute cette application console de test: il n'y a jamais d'appel explicitesp_unprepare
. J'ai fait quelques recherches et trouvé le message suivant sur les forums MSDN:SqlCommand - Se préparer ou ne pas se préparer?
La réponse acceptée contient un tas d'informations, mais les points saillants sont:
J'ai également trouvé le message suivant de l'équipe SQLCAT, qui semble être lié, mais pourrait simplement être un problème spécifique à ODBC alors que SqlClient se nettoie correctement lors de la suppression de SqlConnection. Il est difficile de dire que le post SQLCAT ne mentionne aucun test supplémentaire qui pourrait aider à prouver cela comme une cause, comme l'effacement du pool de connexions, etc.
Méfiez-vous de ces instructions SQL préparées
CONCLUSION
Étant donné que:
SqlCommand.Prepare()
semble être que vous n'avez pas besoin de soumettre à nouveau le texte de la requête sur le réseau,sp_prepare
etsp_prepexec
stocker le texte de la requête dans la mémoire de la connexion (c'est-à-dire la mémoire SQL Server)Je recommande contre l' appel
SqlCommand.Prepare()
parce que le seul avantage potentiel est de sauver les paquets réseau alors que la baisse prend plus de mémoire de serveur. Bien que la quantité de mémoire consommée soit probablement très faible dans la majorité des cas, la bande passante réseau est rarement un problème, car la plupart des serveurs de base de données sont directement connectés aux serveurs d'applications via des connexions minimales de 10 mégabits (plus probablement 100 mégabits ou gigabits de nos jours) ( et certains sont même sur la même boîte ;-). Cela et la mémoire sont presque toujours une ressource plus rare que la bande passante réseau.Je suppose que pour quiconque écrit un logiciel pouvant se connecter à plusieurs bases de données, la commodité d'une interface standard pourrait changer cette analyse coûts / avantages. Mais même dans ce cas, je dois croire qu'il est encore assez facile d'abstraire une interface DB "standard" qui permet à différents fournisseurs (et donc des différences entre eux, comme le fait de ne pas avoir besoin d'appeler
Prepare()
) étant donné que cela est un objet de base Programmation orientée que vous faites probablement déjà dans votre code d'application ;-).la source
sp_prepare
dans l'appel àsp_executesql
, juste pour être sûr. Pour l'étape 10, oui, j'ai fait plus de tests hier et j'ai vu quelques occasions avec des poignées différentes poursp_prepare
, mais toujours jamais pareillessp_executesql
. Je vais tester une dernière chose et mettre à jour ma réponse.sp_executesql
qu'il ne peut pas ou ne le fait pas. Mais quoi qu'il en soit, le temps d'analyse est toujours activésp_prepare
si le plan a été supprimé du cache, je supprimerai donc cette partie de ma réponse (intéressante mais non pertinente). Cette partie était de toute façon plus intéressante, car elle ne répondait pas à votre question directe. Tout le reste s'applique toujours.Je dirais que la méthode Prepare a un monde SqlCommand de valeur limitée, pas qu'elle soit entièrement inutile. L'un des avantages est que Preparer fait partie de l'interface IDbCommand que SqlCommand implémente. Cela permet au même code de s'exécuter sur d'autres fournisseurs de SGBD (qui peuvent nécessiter la préparation) sans logique conditionnelle pour déterminer si la préparation doit être appelée ou non.
Préparer n'a aucune valeur avec le fournisseur .NET pour SQL Server en dehors de ces cas d'utilisation, AFAIK.
la source