2009-09-25 8 views
3

dire que j'écris la requête:MS SQL Server, insérer plusieurs

INSERT INTO DestinationTable 
(ColumnA, ColumnB, ColumnC, etc.) 
SELECT FROM SourceTable 
(ColumnA, ColumnB, ColumnC, etc.) 

Et ma table source a 22 millions de lignes.

Le serveur SQL remplit mon disque dur et génère des erreurs.

Pourquoi le serveur SQL ne peut-il pas gérer ma requête?

Dois-je utiliser un curseur et insérer une ligne à la fois? PS - c'est SQL Express 2005, mais je pourrais essayer la version complète. MISE À JOUR: Je tiens également à mentionner que ma table source ne prend qu'environ 1 Go de stockage lorsque je la regarde dans le studio de gestion. Et pourtant, mes 25 Go d'espace disque libre sont en quelque sorte remplis? J'utilise aussi 2 bases de données différentes Source.mdf -> Destination.mdf, je ne sais pas si cela fait une différence.

+0

Pourquoi inséreuse 22 millions de lignes, sûrement toutes ces données ne peuvent pas être nécessaires. –

+1

Tristement c'est. Je ne peux pas donner de détails, mais c'est chaque client pour une entreprise en particulier. – jonathanpeppers

+0

essayez-vous de copier une table? avez-vous essayé "select into"? –

Répondre

8

Mise à jour batch ...

INSERT INTO DestinationTable 
    (ColumnA, ColumnB, ColumnC, etc.) 
SELECT TOP 100000 ColumnA, ColumnB, ColumnC, etc. 
FROM SourceTable 
WHERE NOT EXISTS (SELECT * 
    FROM DestinationTable 
    WHERE DestinationTable.KeyCols = SourceTable.KeyCols) 

WHILE @@ROWCOUNT <> 0 
    INSERT INTO DestinationTable 
     (ColumnA, ColumnB, ColumnC, etc.) 
    SELECT TOP 100000 ColumnA, ColumnB, ColumnC, etc. 
    FROM SourceTable 
    WHERE NOT EXISTS (SELECT * 
     FROM DestinationTable 
     WHERE DestinationTable.KeyCols = SourceTable.KeyCols) 

Il existe plusieurs formules pour traiter les points de reprise, gestion des journaux de fichiers, si vous avez besoin dans un TXN etc

+0

Je pense que ma suggestion d'un curseur pourrait être un peu moins compliqué que cela . Je vais essayer les deux et voir qui fonctionne le mieux. – jonathanpeppers

+6

Je pense qu'un curseur prendrait un an et demi pour insérer toutes vos données;) – womp

+2

@ Jonathan.Peppers: un CURSOR a toujours besoin de ressources, des verrous, peut-être 22m lignes dans tempdb dépend comment vous le déclarez – gbn

1

Ce blog post a plus sur l'importation de données dans SQL Serveur.

Pour la raison pour laquelle votre table se remplit, je voudrais regarder le schéma de la table, et assurez-vous que les dimensions des colonnes sont aussi petites que possible.

Je voudrais vraiment analyser si toutes les données sont nécessaires.

+0

La raison pour laquelle je déplace la table est parce que ma structure de table est la plus petite possible. Les données sont importées par un tiers, ou nous n'aurions pas ce problème. – jonathanpeppers

4

Vous pouvez copier en bloc les données dans un fichier au format natif (édition modifiée de Csv en natif) et l'importer dans la nouvelle table.

Read up the BCP utility here.

+0

22 millions de lignes? – gbn

+0

Je pourrais aussi bien utiliser USPS. – jonathanpeppers

+1

Eh bien, j'utiliserais un fichier .txt délimité au lieu d'un fichier .csv et d'un insert en masse ou SSIS, mais BCP fonctionne correctement. Pour Jonathan, j'importe un fichier de 22 millions d'enregistrements dans ma base de données en utilisant l'insertion en bloc et cela prend 16 minutes. – HLGEM

0

Vous insérez des données d'une manière qui prend en charge une transaction. Il n'existe aucun moyen de désactiver cela via la méthode que vous utilisez, mais vous pouvez le faire en dehors de la portée d'une transaction via d'autres méthodes. Lire ci-dessous:

http://support.microsoft.com/kb/59462

L'approche clé est la suivante:

dboption 'SELECT INTO' true

http://www.mssqlcity.com/FAQ/Devel/select_into.htm

+0

Vraiment? Ceci est un INSERT standard, ne peut pas être "minimalement connecté". Et depuis SQL Server 2000, vous devez utiliser ALTER DATABASE. – gbn

+0

... et le KB est ancien, et même mentionné lorsque l'option s'applique – gbn

2

Vous pouvez essayer de définir le modèle de récupération de base de données "Simple" au lieu de "Full" (la valeur par défaut). Ceci est fait sur la page Options des propriétés de la base de données dans Management Studio. Cela devrait réduire la taille de votre journal de transactions. Une fois l'insertion terminée, vous pouvez toujours définir le modèle de récupération sur Full.

+0

Je vais essayer et voir, je n'aime pas cette solution si elle finit par être une tâche automatisée. – jonathanpeppers

+1

Si la base de données est en récupération complète et que des sauvegardes de journal ont été effectuées, un basculement vers Simple interrompt la chaîne de journalisation. Cela doit être très soigneusement pris en compte dans un environnement de production lorsque la récupération ponctuelle est requise. Après le retour à une sauvegarde complète de la base de données complète doit être prise pour redémarrer la chaîne de journal et permettre d'autres sauvegardes de journal. – GilaMonster

1

Je vous recommande vivement de définir le modèle de récupération de base de données sur BULK_LOGGED lors de l'exécution de telles opérations de données en masse.

Par défaut, la base de données est définie sur un modèle de récupération SIMPLE ou FULL.

Le modèle de récupération complète, qui enregistre toutes les transactions, est destiné à un usage normal. Le modèle de récupération consigné en bloc est destiné à être utilisé temporairement lors d'une opération en masse volumineuse, en supposant qu'il figure parmi les opérations en bloc affectées par le modèle de récupération consigné en bloc (pour plus d'informations, voir Opérations pouvant être effectuées). Minimalement enregistré à msdn.microsoft.com/en-us/library/ms191244.aspx).

modèle de récupération BULK_LOGGED enregistre au minimum les opérations

vous pouvez le faire en utilisant ci-dessous extrait de code

--Determine the recovery model currently used for the database 

    SELECT name AS [Database Name], 
    recovery_model_desc AS [Recovery Model] 
    FROM sys.databases 
    WHERE name=<database_name> ; 

    --Remember this recovery model so that you can switch back to the same later 

    --set the database recovery model to BULK_LOGGED 

    ALTER DATABASE <database_name> SET RECOVERY BULK_LOGGED; 

    --Run your heavy data insert tasks 
    INSERT INTO DestinationTable 
    (ColumnA, ColumnB, ColumnC, etc.) 
    SELECT FROM SourceTable 
    (ColumnA, ColumnB, ColumnC, etc.) 

    /*Again set the database recovery model to FULL or SIMPLE 
    (the result which we had got from first query)*/ 

    ALTER DATABASE <database_name> SET RECOVERY FULL; 
    --OR 
    ALTER DATABASE <database_name> SET RECOVERY SIMPLE; 

* Remarque - S'il vous plaît faire garder la patience lors de l'opération en vrac est en cours de traitement * [: P]

Je l'ai fait plusieurs fois auparavant. Faites-moi savoir si cela vous a aidé.

Vous pouvez consulter ci-dessous l'article MSDN pour plus de détails de la commutation entre les modèles de récupération - Considérations pour passer de la pleine ou journalisation en bloc modèle de récupération à msdn.microsoft.com/en-us/library/ms190203.aspx

+0

Je vais essayer, le réglage à SIMPLE n'a pas trop d'effet. Il a encore erré finalement. – jonathanpeppers

+0

Offcourse .. Les modèles de récupération FULL et SIMPLE sont bien trop derrière BULK_LOGGED en termes de performances pour les opérations de données en vrac. – Aamod

+0

BULK_LOGGED était plus proche mais ne l'a pas tout à fait atteint sur mon système, et même si c'était le cas, n'aurais-je pas à réduire la base de données/les fichiers pour les ramener à une taille acceptable? Je pense que le dosage de l'insert comme la meilleure réponse suggère, est le chemin à parcourir. – jonathanpeppers

0

Le problème avec INSERT INTO ... SELECT (22 millions de lignes) est que tout s'exécute comme une seule transaction. Ainsi, vous devrez probablement remplir le lecteur du journal des transactions même si la base de données est en mode de récupération simple. Insérer une ligne à la fois est une idée horrible, cela prendra une éternité.

L'exportation des données avec BCP, et l'importation en tant que BULK INSERT est probablement la méthode la plus rapide. Mais cela nécessite d'apprendre à utiliser l'utilitaire BCP.

Si vous êtes déterminé à le faire dans T-SQL, vous devez le découper en lots. La méthode INSERT ... SELECT TOP (n) ... WHERE NOT EXISTS dans la réponse précédente fonctionne, mais le temps d'exécution de la clause WHERE peut correspondre. Pour le rendre un peu plus efficace et encore plus compliqué, je remplis parfois une table temporaire avec les valeurs pk pour chaque n lignes en utilisant ROW_NUMBER() OVER (ORDER BY pk) et WHERE rn% (n) = 0. Ensuite, vous pouvez utiliser une boucle avec INSERT INTO ... SELECT ... O p pk> @a ET pk = @b, avec le code approprié pour mettre à jour les variables à chaque itération de la table temporaire. Assurez-vous de ne manquer aucune ligne sur la première ou la dernière itération.

Vous pouvez le faire dans Integration Services, qui peut également faire des insertions en masse. Il y a un livre blanc de Microsoft sur le chargement de téraoctets de données en 30 minutes environ. Ils ont exporté (BCP?) Les données sources dans plusieurs fichiers et créé plusieurs tables avec la même structure que la destination. Puis insérez chaque fichier dans une table vide distincte, et ils peuvent tous s'exécuter avec un minimum d'informations. Et toutes ces importations fonctionnaient comme des processus parallèles distincts. Enfin, utilisez les commandes de partitionnement de table pour fusionner chaque table d'importation dans la table de destination.

Charge un téraoctet en 30 minutes: https://technet.microsoft.com/en-us/library/dd537533(v=sql.100).aspx

Questions connexes