Le moyen le plus rapide d'insérer 30 000 lignes dans une table temporaire sur SQL Server avec C #
J'essaie de trouver comment je peux améliorer ma performance de l'insert dans une table temporaire dans SQL Server à l'aide de c#. Certaines personnes disent que je devrais utiliser SQLBulkCopy mais je dois faire quelque chose de mal, comme il semble fonctionner beaucoup plus lent que de construire un SQL insert chaîne à la place.
Mon code pour créer la table à l'aide de SQLBulkCopy est ci-dessous:
public void MakeTable(string tableName, List<string> ids, SqlConnection connection)
{
SqlCommand cmd = new SqlCommand("CREATE TABLE ##" + tableName + " (ID int)", connection);
cmd.ExecuteNonQuery();
DataTable localTempTable = new DataTable(tableName);
DataColumn id = new DataColumn();
id.DataType = System.Type.GetType("System.Int32");
id.ColumnName = "ID";
localTempTable.Columns.Add(id);
foreach (var item in ids)
{
DataRow row = localTempTable.NewRow();
row[0] = item;
localTempTable.Rows.Add(row);
localTempTable.AcceptChanges();
}
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
{
bulkCopy.DestinationTableName = "##" + tableName;
bulkCopy.WriteToServer(localTempTable);
}
}
De cette façon, mes inserts de prendre du temps pour s'exécuter. J'ai obtenu mon insère plus rapide de travailler d'une autre manière:
J'ai créé les inserts peu comme une chaîne de caractères et la rejoint dans mon SQL create table temp déclaration:
Création de plaquettes de chaîne:
public string prepareInserts(string tableName, List<string> ids)
{
List<string> inserts = new List<string>();
var total = ids.Select(p => p).Count();
var size = 1000;
var insert = 1;
var skip = size * (insert - 1);
var canPage = skip < total;
while (canPage)
{
inserts.Add(" insert into ##" + tableName + @" (ID) values " + String.Join(",", ids.Select(p => string.Format("({0})", p))
.Skip(skip)
.Take(size)
.ToArray()));
insert++;
skip = size * (insert - 1);
canPage = skip < total;
}
string joinedInserts = String.Join("\r\n", inserts.ToArray());
return joinedInserts;
}
De les utiliser dans l'instruction SQL après la création de la requête:
inserts = prepareInserts(tableName, ids);
var query = @"IF EXISTS
(
SELECT *
FROM tempdb.dbo.sysobjects
WHERE ID = OBJECT_ID(N'tempdb..##" + tableName + @"')
)
BEGIN
DELETE FROM ##" + tableName + @"
END
ELSE
BEGIN
CREATE TABLE ##" + tableName + @"
(ID int)
END " + inserts;
var command = new SqlCommand(query, sqlConnection);
...
Depuis que j'ai vu des gens qui me disent (sur stack exchange https://dba.stackexchange.com/questions/44217/fastest-way-to-insert-30-thousand-rows-in-sql-server/44222?noredirect=1#comment78137_44222 ) Que je devrais utiliser SQLBulkCopy et qui serait plus rapide je crois que je devrais améliorer la façon dont je le fais. Donc, si quelqu'un peut suggérer comment je peux améliorer mon SQLBulkCopy code OU me dire si il y a une meilleure instruction insert qui peut améliorer mes performances de l'application de ce serait génial.
source d'informationauteur Jenninha
Vous devez vous connecter pour publier un commentaire.
Votre problème peut être dans
localTempTable.AcceptChanges();
Car il valider vos modifications.Si vous ne le prochain , je pense qu'il va courir plus vite
De MSDN - ensemble de données.AcceptChanges
J'exécute ce code moi-même avec Chronomètre objets à mesurer le temps. C'est le AcceptChanges dans chaque itération qui fait aller lentement.
Résultat lorsque AccpetChanges est à l'intérieur de boucle foreach
Et quand il n'est pas
Différence est de 3 ordres de grandeur 🙂
Utilisation IDataReader et il va courir encore plus vite
au lieu de
cmd.ExecuteNonQuery();
Exécuter