2009-03-10 6 views
2

J'ai une procédure stockée très simple:Comment optimiser plusieurs appels dans mon code .net à une procédure stockée triviale?

create procedure spFoo(v varchar(50)) 
as 
insert into tbFoo select v 

J'ai 50 valeurs à insérer dans tbFoo, ce qui signifie que dans mon code C# J'appelle spFoo 50 fois. C'est une façon assez inefficace de faire cela, surtout s'il y a un décalage entre mon programme et la base de données.

Que faites-vous habituellement dans cette situation? J'utilise SQL Server 2008, mais il est probablement sans rapport.

Répondre

6

Si votre problème est plusieurs lignes en essayant d'être passé dans alors que de SQL Server 2008, vous avez un nouveau type de paramètre Table-Valued. Ce qui vous permet de transmettre une .Net Datatable directement dans une procédure stockée via un .NET SQLParamter de type structuré.

tvpParam.SqlDbType = SqlDbType.Structured 

Toutefois, si le problème est qu'il ya 50 colonnes de 1 ligne que vous essayez de remplir alors vous seriez mieux les transmettre tous dans les paramètres et changer la procédure plutôt que comme séparés en essayant d'obtenir lisse soit code ou T-SQL.

Il existe un bon article qui montre comment utiliser les paramètres de table dans SQL Server et via .NET dans C# et VB.Net. J'espère que cela aide.

2

Cela dépend s'il s'agit d'un goulot d'étranglement ou non.
Si ce n'est pas le cas, je ne m'inquiéterais pas. Si tel est le cas, vous pouvez passer tous les 50 éléments à une procédure stockée, sous la forme d'une chaîne par exemple.
La procédure stockée peut ensuite séparer les valeurs, puis appeler votre procédure de création selon vos besoins.
Donc, vous appelez SQL une fois, et il ferait 50 insertions.

3

En fait, qu'est-ce qui est inefficace ici? Si vous ne voulez pas utiliser une sorte d'INSULSE EN VRAC, vous devrez l'appeler 50 fois. Néanmoins, si vous avez utilisé une instruction préparée et que vous remplacez simplement la valeur du paramètre à chaque exécution, cela devrait aller très vite.

En outre, 50 insertions/appels sp est en réalité rien. Allez tout de suite avec ça.

0

Passez les valeurs à insérer en tant que paramètre XML. Vous pouvez ensuite utiliser une requête XPath pour insérer en bloc les données.

4

En fait, une fonctionnalité intéressante de SQL Server 2008 est table valued parameters.

configuration:

create type fooTableType as table (v varchar(50)); 
go 

create proc spFoo(@t fooTableType readonly) as 
    insert into tbFoo(v) select v from @t 
go 

alors votre code C# SREG:

declare @t as fooTableType 
insert @t(v) values('beyond'),('all'),('recognition') 
exec spFoo(@t) 

est ici un code C# rude pour le faire:

using (SqlCommand cmd=new SqlCommand()) { 
    StringBuilder sql = new StringBuilder(); 
    for(int i=0; i<50; i++) { 
    sql.AppendFormat(",(@v{i})",i); 
    cmd.Parameters.AddWithValue("@v"+i.ToString(),values[i]); 
    } 
    cmd.CommandText = "declare @t as fooTableType; insert @t(v) values" + 
        sql.ToString().Substr(1) + "; exec spFoo(@t);" 
    cmd.CommandType = CommandType.Text; 
    cmd.Connection = myConnection; 
    cmd.ExecuteNonQuery(); 
} 

Je serais plutôt d'accord qu'une telle optimisation n'est pas absolument nécessaire. Peut-être que c'est OCD mais je ne serais pas capable de le laisser comme une boucle de cmd.ExecuteNonQuery().

Vérifiez le answer de CertifiedCrazy pour une version plus propre du code C#. Notez également que cette technique est limitée à 2 100 paramètres au total - c'est une limitation du protocole TDS sous-jacent.

+0

Pouvez-vous appeler ce sproc à partir du code .NET et si oui, auriez-vous l'affichage en place un code d'exemple qui montre comment? Merci. –

+1

En fait, trouvé: http://msdn.microsoft.com/en-us/library/bb675163.aspx. Bonnes choses –

+0

À mon avis, ce n'est pas aussi bien rangé ou maintenable que d'autres codes. En fait, je préférerais pré-préparer la commande et faire une boucle 50 fois juste en changeant le paramètre. Ou encore mieux, utilisez tvpParam.SqlDbType = SqlDbType.Structured selon la réponse de CertifiedCrazy. – MatBailie

2

Lot les appels en créant des paramètres @ v0 par @ V49, il est donc seulement 1 réseau aller-retour:

using (var cmd = new SqlCommand()) { 
    for (int i = 0; i < 50; i++) { 
     string paramName = "@v" + i.ToString(); 
     cmd.CommandText += string.Format("EXEC spFoo " + paramName + ";"); 
     cmd.Parameters.AddWithValue(paramName, values[i]); 
    } 

    cmd.ExecuteNonQuery(); 
} 
+1

Intéressant ... n'avait pas vu cette approche avant –

+0

@Mark Brackett Upvoted! C'est une approche parfaite pour mes exigences de projet – waltmagic

Questions connexes