web-dev-qa-db-fra.com

Comment faire des insertions très rapides dans SQL Server 2008

J'ai un projet qui consiste à enregistrer des données d'un appareil directement dans une table sql.

Je fais très peu de traitement en code avant d'écrire sur le serveur sql (2008 express soit dit en passant)

j'utilise généralement la méthode ExecuteNonQuery de la classe sqlhelper et je transmets un nom de proc stocké et une liste de paramètres attendus par le SP SP.

C'est très pratique, mais j'ai besoin d'un moyen beaucoup plus rapide de le faire.

Merci.

26
Charles Okwuagwu

ExecuteNonQuery avec une instruction INSERT, ou même une procédure stockée, vous permettra d'accéder à des milliers d'insertions par seconde sur Express. 4000-5000/sec sont facilement réalisables, je le sais pour un fait.

Ce qui ralentit généralement les mises à jour individuelles est le temps d'attente pour le vidage de journal et vous devez en tenir compte. La solution la plus simple consiste à simplement valider par lots. Par exemple. valider toutes les 1000 insertions ou toutes les secondes. Cela remplira les pages de journal et amortira le coût de la purge de journal sur toutes les insertions d'une transaction.

Avec les validations par lots, vous aurez probablement un goulot d'étranglement sur les performances d'écriture du journal du disque, ce que vous ne pouvez rien faire à part changer le matériel (aller raid 0 stripe sur le journal).

Si vous rencontrez des goulots d'étranglement antérieurs (peu probable), alors vous pouvez examiner les instructions de traitement par lots, c.-à-d. envoyer un seul lot T-SQL avec plusieurs insertions dessus. Mais cela porte rarement ses fruits.

Bien sûr, vous devrez réduire la taille de vos écritures au minimum, ce qui signifie réduire la largeur de votre table aux colonnes minimalement nécessaires, éliminer les index non clusterisés, éliminer les contraintes inutiles. Si possible, utilisez un segment de mémoire au lieu d'un index cluster, car les insertions de segment de mémoire sont nettement plus rapides que celles à index cluster.

Il n'est pas nécessaire d'utiliser l'interface d'insertion rapide (par exemple, SqlBulkCopy). En utilisant INSERTS ordinaires et ExecuteNoQuery sur les validations par lots, vous épuiserez le débit d'écriture séquentielle du lecteur beaucoup plus rapidement que la nécessité de déployer l'insertion en bloc. L'insertion en bloc est nécessaire sur les machines connectées rapides SAN, et vous mentionnez Express donc ce n'est probablement pas le cas. Il y a une perception du contraire, mais c'est simplement parce que les gens ne se rendent pas compte que l'insertion en bloc leur donne une validation par lots, et c'est la validation par lots qui accélère, et non l'insertion en bloc.

Comme pour tout test de performance, assurez-vous d'éliminer le caractère aléatoire et préallouez la base de données et le journal, vous ne voulez pas frapper la base de données ou enregistrer un événement de croissance pendant les mesures de test ou pendant la production, c'est trop amateur .

46
Remus Rusanu

l'insertion en vrac serait la plus rapide car elle est connectée de façon minimale

.NET possède également la classe SqlBulkCopy

4
SQLMenace

Voici un bon moyen d'insérer un grand nombre d'enregistrements à l'aide de variables de table ...

... mais mieux de le limiter à 1000 enregistrements à la fois car les variables de table sont "en mémoire"

Dans cet exemple, je vais insérer 2 enregistrements dans une table avec 3 champs - CustID, Firstname, Lastname

--first create an In-Memory table variable with same structure
--you could also use a temporary table, but it would be slower

declare @MyTblVar table (CustID int, FName nvarchar(50), LName nvarchar(50))

insert into @MyTblVar values (100,'Joe','Bloggs')

insert into @MyTblVar values (101,'Mary','Smith')

Insert into MyCustomerTable

Select * from @MyTblVar
2
user2696172

Cela se fait généralement au moyen d'un BULK INSERT . Fondamentalement, vous préparez un fichier, puis émettez le BULK INSERT et SQL Server copie toutes les données du fichier dans la table avec la méthode rapide possible.

Il a quelques restrictions (par exemple, il n'y a aucun moyen de faire un type de comportement "mettre à jour ou insérer" si vous avez des lignes éventuellement existantes à mettre à jour), mais si vous pouvez les contourner, il est peu probable que vous trouviez quelque chose de bien plus rapide.

2
Dean Harding

Les éléments qui peuvent ralentir les insertions incluent les index et les lectures ou mises à jour (verrous) sur la même table. Vous pouvez accélérer des situations comme la vôtre en évitant les deux et en insérant des transactions individuelles dans une table d'attente distincte sans index ni autre activité. Ensuite, regroupez la table de maintien sur la table principale un peu moins fréquemment.

2
Joel Coehoorn

Si vous voulez dire à partir de .NET, utilisez SqlBulkCopy

1
Mitch Wheat

Il ne peut vraiment aller aussi vite que votre SP s'exécutera. Assurez-vous que les tables sont correctement indexées et si vous avez un index clusterisé, assurez-vous qu'il a un étroit, unique, croissant Assurez-vous que les index et contraintes restants (le cas échéant) n'ont pas beaucoup de surcharge.

Vous ne devriez pas voir beaucoup de surcharge dans la couche ADO.NET (je n'utiliserais pas nécessairement une autre bibliothèque .NET au-dessus de SQLCommand). Vous pouvez peut-être utiliser les méthodes ADO.NET Async afin de mettre en file d'attente plusieurs appels vers le proc stocké sans bloquer un seul thread dans votre application (cela pourrait potentiellement libérer plus de débit que toute autre chose - tout comme avoir plusieurs machines à insérer dans la base de données ).

En dehors de cela, vous devez vraiment nous en dire plus sur vos besoins.

1
Cade Roux