10

Je ne sais pas si c'est un problème avec la manière dont je les utilise ou avec l'implémentation de Microsoft, mais les paramètres de valeur de table SQL 2008 sont extrêmement lents.Problèmes avec les performances des paramètres de table

Généralement, si j'ai besoin d'utiliser un TVP c'est parce que j'ai beaucoup d'enregistrements - actuellement ils semblent être inutilement lents pour quelque chose de plus que le moins d'enregistrements.

Je les appelle en .Net comme ceci:

// get the data 
DataTable data = GetData(); 

com.CommandText = "sprocName" 

// create the table-value parameter 
var tvp = com.Parameters.AddWithValue("data", data); 
tvp.SqlDbType = SqlDbType.Structured; 

com.ExecuteNonQuery(); 

J'ai couru profileur pour voir pourquoi, et l'instruction SQL réelle est quelque chose comme ceci:

declare @data table ... 

insert into @data (... fields ...) values (... values ...) 
-- for each row 
insert into @data (... fields ...) values (... values ...) 

sprocName(@data) 

C'est vraiment lent manière de le faire cependant. Il serait beaucoup plus rapide si elle a fait ceci:

insert into @data (... fields ...) 
values (... values ...), 
     (... values ...), 
     -- for each row 
     (... values ...) 

Je ne sais pas pourquoi il n'utilise pas la plus récente, la syntaxe beaucoup plus rapide. Ou même tout ce qu'il fait sous le capot avec SqlBulkCopy.

La nouvelle syntaxe a été ajoutée dans SQL 2008, mais il en va de même pour les TVP (je pense).

Y at-il une option pour le faire faire? Ou quelque chose qui me manque?

+3

Si des traces SQL profileurs sont marqués comme RPC (non lots), cela signifie que le texte affiché n'est pas un vrai texte qui a été le fil transmis , mais un texte reconstruit à partir des paramètres RPC réels. Cela n'explique pas pourquoi c'est lent, mais cela peut ne pas être significatif. –

Répondre

3

Voir la section "Paramètres table Valued par rapport à des opérations BULK INSERT"
http://msdn.microsoft.com/en-us/library/bb510489.aspx

Citation: "... paramètres de valeur table donnent de bons résultats pour insérer moins de 1000 lignes."

Il dispose également d'une table pour montrer quelle technologie utiliser en fonction de la vitesse des opérations d'insertion. J'espère que cela aide, bonne chance.

+0

Cheers. Cependant, en pratique, même pour une table de quelques centaines de lignes, les TVP sont toujours sensiblement plus lents que l'option de liste de valeurs et même plus lent que 'SqlBulkCopy' après le premier appel (la première fois que' SqlBulkCopy' 2s pour une raison quelconque). – Keith

+0

@Keith et Robert, les informations contenues dans cette documentation liée doivent être prises en contexte. S'il vous plaît voir ma réponse, et en particulier le Livre blanc auquel je suis lié en bas. –

+1

@srutzky, merci c'est une bonne réponse. – Robert

9

Si les TVP sont «nettement plus lents» que les autres options, il est fort probable que vous ne les implémentiez pas correctement.

  1. Vous ne devriez pas utiliser un DataTable, à moins que votre application ne l'utilise en dehors de l'envoi des valeurs au TVP. L'utilisation de l'interface IEnumerable<SqlDataRecord> est plus rapide et utilise moins de mémoire car vous ne dupliquez pas la collection en mémoire uniquement pour l'envoyer à la base de données. Je cette documentation dans les endroits suivants:
  2. Vous ne devez pas utiliser AddWithValue pour SqlParameter, bien que cela ne soit pas un problème de performances. Mais encore, il devrait être:

    SqlParameter tvp = com.Parameters.Add("data", SqlDbType.Structured); 
    tvp.Value = MethodThatReturnsIEnumerable<SqlDataRecord>(MyCollection); 
    
  3. TVPs sont Tableau variables et en tant que telles ne tiennent pas de statistiques. En d'autres termes, ils indiquent n'avoir qu'une ligne dans l'Optimiseur de requêtes.Ainsi, dans votre proc, soit:
    • Utilisez recompilation niveau de déclaration sur toutes les questions en utilisant le PVT pour autre chose qu'un simple SELECT: OPTION (RECOMPILE)
    • Créer une table temporaire locale (simple #) et copier le contenu du PVT dans la table temporaire

en ce qui concerne la raison pour laquelle vous voyez:

insert into @data (... fields ...) values (... values ...) 
-- for each row 
insert into @data (... fields ...) values (... values ...) 

au lieu de:

insert into @data (... fields ...) 
values (... values ...), 
     (... values ...), 

IF qui est en fait ce qui se passe, alors:

  • Si les inserts sont en cours dans une transaction alors il n'y a pas de différence réelle performance
  • La valeur plus récente liste-syntaxe VALUES (row1), (row2), (row3)) est limité à quelque chose comme 1000 lignes et donc pas une option viable pour les TVP qui n'ont pas cette limite.

S'il vous plaît voir aussi ce livre blanc de l'équipe consultative client SQL Server: Maximizing Throughput with TVP

Questions connexes