Potřebuji přesunout celou hromadu (100+) velkých (miliony řádků) tabulek z jedné databáze SQL2008 do druhé.
Původně jsem použil Průvodce importem/exportem, ale ve všech cílových tabulkách chyběly primární a cizí klíče, indexy, omezení, triggery atd. (Sloupce identity byly také převedeny na obyčejné INTs, ale myslím, že jsem právě zmeškal zaškrtávací políčko v kouzelník.)
Jaký je správný způsob, jak toho dosáhnout?
Pokud by to bylo jen pár tabulek, vrátil bych se ke zdroji, skriptoval definici tabulky (se všemi indexy atd.) A potom spustil části skriptu pro vytvoření indexu v cíli. Ale s tolika tabulkami se to zdá nepraktické.
Pokud by nebylo tolik dat, mohl bych pomocí průvodce „Vytvořit skripty ...“ skriptovat zdroj, včetně dat, ale 72m řádkový skript prostě nevypadá jako dobrý nápad!
Vlastně jsme to provedli pomocí mnoha ručních skriptů ve spojení s Průvodcem importem, ale dnes ráno jsem našel lepší odpověď s laskavým svolením článek blogu Tibora Karasziho .
Část naší frustrace zde spočívala v tom, že SQL 2000 „Průvodce importem/exportem DTS“ to ve skutečnosti téměř usnadňuje výběrem možnosti „Kopírovat objekty a data“:
Tato třetí možnost je ta, která obsahuje možnost zahrnout indexy/triggery atd.:
Tato možnost byla [~ # ~] odstraněna [~ # ~] z SQL 2005/2008 Průvodce importem. Proč? Žádný nápad:
V roce 2005/2008 musíte zřejmě ručně vytvořit balíček SSIS v BIDS a použít Transfer SQL Server Objects Task , který obsahuje všechny stejné možnosti, jaké byly v průvodce 2000:
Nejspolehlivějším a nejefektivnějším způsobem přesunu dat do nové databáze by bylo skriptování tabulek a použití SSIS k přenosu dat.
Zvažoval bych skriptovat tabulku ven, nebo použít porovnávací nástroje (např. Red Gate) k vygenerování tabulek v cílové databázi. Bez indexů nebo omezení dosud.
Pak bych uvažoval o obnovení databáze s jiným jménem na stejném serveru a provedení
INSERT newdb.dbo.newtable SELECT * FROM olddb.dbo.oldtable
.. pro každou tabulku, se SET IDENTITY INSERT ON V případě potřeby
Poté bych po načtení dat přidal indexy a omezení.
Závisí to na vaší úrovni komfortu s SSIS (mrdennyho odpověď), nebo pokud dáváte přednost surovému SQL.
Chtěl bych přidat k odpovědi pana Dennyho: Script out the tables schéma potom pomocí BCP přesunout data. Pokud nejste obeznámeni s SSIS, pak by mělo být snadné používat BCP a šarže. Pro miliony řádků nic nepřekonává BCP (hromadné vložení) :).
Já jsem ten, kdo je s SSIS úplně nepříjemný.
Když zdrojové tabulky nemají žádné sloupce identity
T-SQL nyní generuje příkazy Select * do ...
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
Tím se pro každou tabulku vytvoří řádek, který se má zkopírovat
select * into [Table1] from [linked_server].[source_db].[dbo].[Table1];
V případě, že tabulky obsahují sloupce identity, skriptuji tabulky včetně vlastnosti identity a primárních klíčů.
Nepoužívám vložení do ... select ... v tomto případě pomocí propojeného serveru, protože nejde o hromadnou techniku. Pracuji na některých skriptech PowerShell podobných [této SO otázka 1 , ale stále pracuji na zpracování chyb. Opravdu velké tabulky mohou způsobit nedostatek paměti chyby, protože celá tabulka je načtena do paměti před jejím odesláním přes SQLBulkCopy do databáze.
Rekreace indexů atd. Je podobná jako v předchozím případě. Tentokrát mohu přeskočit rekreaci primárních klíčů.
K vytvoření všech tabulek můžete použít srovnávací nástroje, které porovnají schémata a data databáze a nejprve synchronizují prázdné schéma databáze s původním db.
Poté synchronizujte data z původní databáze s novou (všechny tabulky jsou tam, ale všechny jsou prázdné) a vložte záznamy do tabulek
K tomu používám ApexSQL Diff a ApexSQL Data Diff , ale existují i jiné podobné nástroje.
Dobrá věc na tomto procesu je, že nemusíte skutečně synchronizovat databáze pomocí nástroje, protože to může být docela bolestivé pro miliony řádků.
Můžete pouze vytvořit skript INSERT INTO SQL (nenechte se překvapit, pokud je to několik koncertů) a spusťte jej.
Protože tak velké skripty nelze otevřít ani v SQL Server Management Studio, používám sqlcmd nebo osql
Jak @mrdenny zmínil -
Namísto použití SSIS použijte k vložení dat BCP
bcp z dat pomocí skriptu níže. nastavte SSMS v textovém režimu a zkopírujte výstup generovaný skriptem do souboru 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)
Spusťte soubor bat, který vygeneruje soubory .dat ve složce, kterou jste určili.
Spustit pod skript na
--- 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)
Spusťte výstup pomocí SSMS pro vložení dat zpět do tabulek.
Toto je velmi rychlá metoda BCP, protože používá nativní režim.