Ich muss eine ganze Reihe (100+) großer (Millionen von Zeilen) Tabellen von einer SQL2008-Datenbank in eine andere verschieben.
Ich habe ursprünglich nur den Import/Export-Assistenten verwendet, aber in allen Zieltabellen fehlten Primär- und Fremdschlüssel, Indizes, Einschränkungen, Trigger usw. (Identitätsspalten wurden ebenfalls in einfache INTs konvertiert, aber ich glaube, ich habe gerade ein Kontrollkästchen im Feld verpasst Magier.)
Was ist der richtige Weg, um dies zu tun?
Wenn dies nur ein paar Tabellen wären, würde ich zur Quelle zurückkehren, die Tabellendefinition (mit allen Indizes usw.) skripten und dann die Indexerstellungsteile des Skripts auf dem Ziel ausführen. Bei so vielen Tabellen scheint dies jedoch unpraktisch.
Wenn es nicht so viele Daten gäbe, könnte ich den Assistenten "Skripte erstellen ..." verwenden, um die Quelle einschließlich der Daten zu skripten, aber ein Skript mit 72 m Zeilen scheint einfach keine gute Idee zu sein!
Wir haben es tatsächlich mit vielen manuellen Skripten in Verbindung mit dem Import-Assistenten gemacht, aber heute Morgen habe ich eine bessere Antwort gefunden, mit freundlicher Genehmigung von Tibor Karaszis Blog-Artikel .
Ein Teil unserer Frustration war, dass der SQL 2000 "DTS-Import/Export-Assistent" dies durch Auswahl von "Objekte und Daten kopieren" fast trivial einfach macht:
Diese dritte Option enthält die Möglichkeit, Indizes/Trigger usw. einzuschließen:
Diese Option wurde [~ # ~] aus dem Importassistenten SQL 2005/2008 [[# # ~] entfernt. Warum? Keine Ahnung:
In 2005/2008 müssen Sie anscheinend manuell ein SSIS-Paket in BIDS erstellen und SQL Server Objects Task übertragen verwenden, das dieselben Optionen enthält, die sich in befanden der 2000-Assistent:
Das Ausschreiben der Tabellen und das anschließende Übertragen der Daten mit SSIS ist die zuverlässigste und effektivste Methode, um die Daten in die neue Datenbank zu verschieben.
Ich würde in Betracht ziehen, die Tabelle zu skripten oder ein Vergleichstool (z. B. Red Gate) zu verwenden, um die Tabellen in der Zieldatenbank zu generieren. Noch ohne Indizes oder Einschränkungen.
Dann würde ich in Betracht ziehen, die Datenbank mit einem anderen Namen auf demselben Server wiederherzustellen und dies zu tun
INSERT newdb.dbo.newtable SELECT * FROM olddb.dbo.oldtable
.. für jede Tabelle mit SET IDENTITY INSERT ON, falls erforderlich
Dann würde ich nach dem Laden der Daten Indizes und Einschränkungen hinzufügen.
Dies hängt von Ihrem Komfortniveau mit SSIS (Antwort von mrdenny) ab oder davon, ob Sie Raw SQL bevorzugen.
Ich würde die Antwort von Herrn Denny ergänzen: Schreiben Sie das Tabellenschema aus und verschieben Sie die Daten mit BCP. Wenn Sie mit SSIS nicht vertraut sind, sollte die Verwendung von BCP und Batches einfach sein. Für Millionen von Zeilen geht nichts über BCP (Bulk Insert) :).
Ich bin derjenige, der sich mit SSIS völlig unwohl fühlt.
Wenn die Quelltabellen keine Identitätsspalten haben
Nun generiert das T-SQL die Select * in ... -Anweisungen
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
Dies erzeugt eine Zeile für jede Tabelle, die wie kopiert werden soll
select * into [Table1] from [linked_server].[source_db].[dbo].[Table1];
Für den Fall, dass die Tabellen Identitätsspalten enthalten, skripte ich die Tabellen einschließlich Identitätseigenschaft und Primärschlüssel.
Ich verwende in diesem Fall nicht das Einfügen in ... auswählen ... über einen Verbindungsserver, da dies keine Massentechnik ist. Ich arbeite an einigen PowerShell-Skripten ähnlich [this SO question 1 , aber ich arbeite immer noch an der Fehlerbehandlung. Wirklich große Tabellen können zu Speichermangel führen Fehler, da eine ganze Tabelle in den Speicher geladen wird, bevor sie über SQLBulkCopy an die Datenbank gesendet wird.
Die Neuerstellung von Indizes usw. ähnelt dem obigen Fall. Dieses Mal kann ich die Neuerstellung der Primärschlüssel überspringen.
Sie können Vergleichstools verwenden, die Datenbankschemata und -daten vergleichen und zuerst ein leeres Datenbankschema mit der ursprünglichen Datenbank synchronisieren, um alle Tabellen zu erstellen.
Synchronisieren Sie dann die Daten aus der ursprünglichen Datenbank mit der neuen (alle Tabellen sind vorhanden, aber alle leer), um die Datensätze in die Tabellen einzufügen
Ich benutze dafür ApexSQL Diff und ApexSQL Data Diff , aber es gibt andere ähnliche Tools.
Das Gute an diesem Prozess ist, dass Sie die Datenbanken nicht mit dem Tool synchronisieren müssen, da dies für Millionen von Zeilen sehr schmerzhaft sein kann.
Sie können einfach ein INSERT INTO SQL-Skript erstellen (wundern Sie sich nicht, wenn es sich um mehrere Gigs handelt) und es ausführen.
Da so große Skripte nicht einmal in SQL Server Management Studio geöffnet werden können, verwende ich sqlcmd oder osql
Wie @mrdenny erwähnt -
Verwenden Sie anstelle von SSIS BCP, um Daten einzufügen
bcp die Daten mit dem folgenden Skript aus. Stellen Sie SSMS in den Textmodus und kopieren Sie die vom folgenden Skript generierte Ausgabe in eine Bat-Datei.
-- 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)
Führen Sie die bat-Datei aus, die die .dat-Dateien in dem von Ihnen angegebenen Ordner generiert.
Führen Sie das folgende Skript auf dem aus
--- 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)
Führen Sie die Ausgabe mit SSMS aus, um Daten wieder in die Tabellen einzufügen.
Dies ist eine sehr schnelle bcp-Methode, da sie den Native-Modus verwendet.