J'ai besoin de déplacer un tas (100+) de grandes tables (des millions de lignes) d'une base de données SQL2008 à une autre.
À l'origine, je viens d'utiliser l'assistant d'importation/exportation, mais toutes les tables de destination manquaient de clés primaires et étrangères, d'index, de contraintes, de déclencheurs, etc. (les colonnes d'identité ont également été converties en INT simples, mais je pense que j'ai raté une case à cocher dans le sorcier.)
Quelle est la bonne façon de procéder?
S'il ne s'agissait que de quelques tables, je retournerais à la source, je rédigerais la définition de la table par script (avec tous les index, etc.), puis j'exécuterais les parties de création d'index du script sur la destination. Mais avec autant de tableaux, cela semble peu pratique.
S'il n'y avait pas vraiment autant de données, je pourrais utiliser l'assistant "Créer des scripts ..." pour créer un script pour la source, y compris les données, mais un script de 72m ne semble tout simplement pas une bonne idée!
Nous l'avons fait en utilisant beaucoup de scripts manuels en conjonction avec l'assistant d'importation, mais ce matin, j'ai trouvé une meilleure réponse, gracieuseté de article de blog de Tibor Karaszi .
Une partie de notre frustration était que le SQL 2000 "Assistant d'importation/exportation DTS" rend cela presque facile en sélectionnant "Copier les objets et les données":
Cette troisième option est celle qui contient la possibilité d'inclure des index/déclencheurs, etc.:
Cette option a été [~ # ~] supprimée [~ # ~] de SQL 2005/2008 Assistant d'importation. Pourquoi? Aucune idée:
En 2005/2008, vous devez apparemment manuellement créer un package SSIS dans BIDS et utiliser Transférer la tâche des objets SQL Server , qui contient toutes les mêmes options que celles présentes dans l'assistant 2000:
Scénariser les tables, puis utiliser SSIS pour transférer les données serait le moyen le plus fiable et le plus efficace de déplacer les données vers la nouvelle base de données.
J'envisagerais de créer un script pour la table ou d'utiliser des outils de comparaison (par exemple, Red Gate) pour générer les tables dans la base de données cible. Sans index ni contraintes pour le moment.
J'envisagerais alors de restaurer la base de données avec un nom différent sur le même serveur et de faire
INSERT newdb.dbo.newtable SELECT * FROM olddb.dbo.oldtable
.. pour chaque table, avec SET IDENTITY INSERT ON si nécessaire
Ensuite, j'ajoutais des index et des contraintes après le chargement des données.
Cela dépend de votre niveau de confort avec SSIS (réponse de mrdenny) ou si vous préférez du SQL brut.
J'ajouterais à la réponse de M. Denny: Scriptez le schéma des tables puis utilisez BCP pour déplacer les données. Si vous n'êtes pas familier avec SSIS, l'utilisation de BCP et des lots devrait être facile à faire. Pour des millions de lignes, rien ne vaut BCP (insert en vrac) :).
Je suis celui qui est complètement mal à l'aise avec SSIS.
Lorsque les tables source n'ont pas de colonnes d'identité
Maintenant, le T-SQL pour générer les instructions Select * into ...
SET NOCOUNT ON
declare @name sysname
declare @sql varchar(255)
declare db_cursor cursor for
select name from sys.tables order by 1
open db_cursor
fetch next from db_cursor into @name
while @@FETCH_STATUS = 0
begin
Set @sql = 'select * into [' + @name + '] from [linked_server].[source_db].[dbo].[' + @name + '];'
print @sql
fetch next from db_cursor into @name
end
close db_cursor
deallocate db_cursor
Cela génère une ligne pour chaque table à copier comme
select * into [Table1] from [linked_server].[source_db].[dbo].[Table1];
Dans le cas où les tables contiennent des colonnes d'identité, je script les tables, y compris la propriété d'identité et les clés primaires.
Je n'utilise pas d'insertion dans ... sélectionnez ... en utilisant un serveur lié dans ce cas, car ce n'est pas une technique en bloc. Je travaille sur certains scripts PowerShell similaires à [this SO question 1 , mais je travaille toujours sur la gestion des erreurs. De très grandes tables peuvent entraîner une perte de mémoire) des erreurs, car une table entière est chargée en mémoire avant d'être envoyée via SQLBulkCopy à la base de données.
La récréation des index, etc. est similaire au cas ci-dessus. Cette fois, je peux sauter la recréation des clés primaires.
Vous pouvez utiliser des outils de comparaison qui comparent les schémas et les données de la base de données et synchronisez d'abord un schéma de base de données vide avec la base de données d'origine, pour créer toutes les tables.
Ensuite, synchronisez les données de la base de données d'origine avec la nouvelle (toutes les tables sont là, mais elles sont toutes vides) pour insérer les enregistrements dans les tables
J'utilise ApexSQL Diff et ApexSQL Data Diff pour cela, mais il existe d'autres outils similaires.
La bonne chose à propos de ce processus est que vous n'avez pas réellement à synchroniser les bases de données à l'aide de l'outil, car cela peut être assez pénible pour des millions de lignes.
Vous pouvez simplement créer un script SQL INSERT INTO (ne soyez pas surpris s'il s'agit de plusieurs concerts) et l'exécuter.
Comme de si gros scripts ne peuvent même pas être ouverts dans SQL Server Management Studio, j'utilise sqlcmd ou osql
Comme l'a mentionné @mrdenny -
Au lieu d'utiliser SSIS, utilisez BCP pour insérer des données
bcp sortir les données en utilisant le script ci-dessous. définissez SSMS en mode texte et copiez la sortie générée par le script ci-dessous dans un fichier bat.
-- save below output in a bat file by executing below in SSMS in TEXT mode
-- clean up: create a bat file with this command --> del D:\BCP\*.dat
select '"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\bcp.exe" ' /* path to BCP.exe */
+ QUOTENAME(DB_NAME())+ '.' /* Current Database */
+ QUOTENAME(SCHEMA_NAME(SCHEMA_ID))+'.'
+ QUOTENAME(name)
+ ' out D:\BCP\' /* Path where BCP out files will be stored */
+ REPLACE(SCHEMA_NAME(schema_id),' ','') + '_'
+ REPLACE(name,' ','')
+ '.dat -T -E -SServerName\Instance -n' /* ServerName, -E will take care of Identity, -n is for Native Format */
from sys.tables
where is_ms_shipped = 0 and name <> 'sysdiagrams' /* sysdiagrams is classified my MS as UserTable and we dont want it */
/*and schema_name(schema_id) <> 'unwantedschema' */ /* Optional to exclude any schema */
order by schema_name(schema_id)
Exécutez le fichier bat qui générera les fichiers .dat dans le dossier que vous avez spécifié.
Exécutez le script ci-dessous sur le
--- Execute this on the destination server.database from SSMS.
--- Make sure the change the @Destdbname and the bcp out path as per your environment.
declare @Destdbname sysname
set @Destdbname = 'destinationDB' /* Destination Database Name where you want to Bulk Insert in */
select 'BULK INSERT '
/*Remember Tables must be present on destination database */
+ QUOTENAME(@Destdbname) + '.'
+ QUOTENAME(SCHEMA_NAME(SCHEMA_ID))
+ '.' + QUOTENAME(name)
+ ' from ''D:\BCP\' /* Change here for bcp out path */
+ REPLACE(SCHEMA_NAME(schema_id), ' ', '') + '_' + REPLACE(name, ' ', '')
+ '.dat'' with ( KEEPIDENTITY, DATAFILETYPE = ''native'', TABLOCK )'
+ char(10)
+ 'print ''Bulk insert for ' + REPLACE(SCHEMA_NAME(schema_id), ' ', '') + '_' + REPLACE(name, ' ', '') + ' is done... '''
+ char(10) + 'go'
from sys.tables
where is_ms_shipped = 0
and name <> 'sysdiagrams' /* sysdiagrams is classified my MS as UserTable and we dont want it */
and schema_name(schema_id) <> 'unwantedschema' /* Optional to exclude any schema */
order by schema_name(schema_id)
Exécutez la sortie à l'aide de SSMS pour réinsérer les données dans les tables.
C'est une méthode bcp très rapide car elle utilise le mode natif.