it-swarm.it

Spostamento di tabelle in un altro database SQL2008 (inclusi indici, trigger, ecc.)

Devo spostare un intero gruppo (100+) di tabelle di grandi dimensioni (milioni di righe) da un database SQL2008 a un altro.

Inizialmente ho usato l'importazione/esportazione guidata, ma in tutte le tabelle di destinazione mancavano chiavi primarie ed esterne, indici, vincoli, trigger, ecc. (Anche le colonne Identity sono state convertite in semplici INT, ma penso di aver perso una casella nella procedura guidata.)

Qual è il modo giusto per farlo?

Se questo fosse solo un paio di tabelle, ritornerei alla fonte, scrivo la definizione della tabella (con tutti gli indici, ecc.), Quindi eseguo le parti di creazione dell'indice dello script sulla destinazione. Ma con così tanti tavoli, questo sembra poco pratico.

Se non ci fossero così tanti dati, potrei usare la procedura guidata "Crea script ..." per scrivere la fonte, inclusi i dati, ma uno script di 72 m di riga non sembra proprio una buona idea!

16
BradC

In realtà l'abbiamo fatto usando molti script manuali insieme alla procedura guidata di importazione, ma questa mattina ho trovato una risposta migliore, per gentile concessione di articolo del blog di Tibor Karaszi .

Parte della nostra frustrazione qui era che il SQL 2000 "DTS Import/Export Wizard" in realtà lo rende quasi banalmente facile selezionando "Copia oggetti e dati":

DTS Import Wizard

Questa terza opzione è quella che contiene la possibilità di includere indici/trigger, ecc:

Advanced Options

Questa opzione è stata [~ # ~] rimossa [~ # ~] da SQL 2005/2008 Import Wizard. Perché? Nessuna idea:

2008 Import Wizard

Nel 2005/2008, apparentemente devi manualmente creare un pacchetto SSIS in BIDS e usare Task Transfer SQL Server Objects , che contiene tutte le stesse opzioni che erano in il mago del 2000:

SSIS Transfer SQL Server Objects Task

9
BradC

Lo scripting delle tabelle, quindi l'utilizzo di SSIS per trasferire i dati sarebbe il modo più affidabile ed efficace per spostare i dati nel nuovo database.

14
mrdenny

Prenderei in considerazione lo scripting della tabella o utilizzerei uno strumento di confronto (ad esempio Red Gate) per generare le tabelle nel database di destinazione. Senza indici o vincoli ancora.

Quindi prenderei in considerazione il ripristino del database con un nome diverso sullo stesso server e il fare

 INSERT newdb.dbo.newtable SELECT * FROM olddb.dbo.oldtable

.. per ogni tabella, con SET IDENTITY INSERT ON se richiesto

Quindi aggiungerei indici e vincoli dopo aver caricato i dati.

Dipende dal tuo livello di comfort con SSIS (la risposta di mrdenny) o se preferisci SQL grezzo.

8
gbn

Aggiungerei alla risposta di Mr Denny: scrivere lo schema delle tabelle e poi usare BCP per spostare i dati. Se non hai familiarità con SSIS, utilizzare BCP e i batch dovrebbe essere semplice. Per milioni di righe, niente è meglio di BCP (inserimento in blocco) :).

6
Marian

Sono quello che è completamente a disagio con SSIS.

Quando le tabelle di origine non hanno colonne di identità

  1. creare un database vuoto sul server di destinazione
  2. creare un server collegato al server di origine sul server di destinazione
  3. eseguire lo script seguente sul database di origine per generare istruzioni select * in ...
  4. eseguire lo script generato dal database di destinazione
  5. script chiavi primarie, indici, trigger, funzioni e procedure dal database di origine
  6. creare questi oggetti con lo script generato

Ora il T-SQL per generare le istruzioni Select * in ...

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

Questo genera una riga per ogni tabella da copiare come

select * into [Table1] from [linked_server].[source_db].[dbo].[Table1];

Nel caso in cui le tabelle contengano colonne di identità, scrivo le tabelle includendo proprietà di identità e chiavi primarie.

Non utilizzo insert in ... select ... utilizzando un server collegato in questo caso, poiché questa non è una tecnica di massa. Sto lavorando ad alcuni script di PowerShell simili a [this SO domanda 1 , ma sto ancora lavorando sulla gestione degli errori. Tabelle davvero grandi possono causare memoria insufficiente errori, poiché un'intera tabella viene caricata in memoria, prima che venga inviata tramite SQLBulkCopy al database.

La ricreazione di indici ecc. È simile al caso precedente. Questa volta posso saltare la ricreazione delle chiavi primarie.

4
bernd_k

È possibile utilizzare strumenti di confronto che confrontano schemi e dati di database e sincronizzano prima uno schema di database vuoto con il db originale, per creare tutte le tabelle.

Quindi, sincronizza i dati dal database originale con quello nuovo (tutte le tabelle sono presenti, ma sono tutte vuote) per inserire i record nelle tabelle

Per questo uso ApexSQL Diff e ApexSQL Data Diff per questo, ma ci sono altri strumenti simili.

La cosa positiva di questo processo è che non è necessario sincronizzare effettivamente i database usando lo strumento, poiché questo può essere abbastanza doloroso per milioni di righe.

Puoi semplicemente creare uno script INSERT INTO SQL (non stupirti se si tratta di più concerti) ed eseguirlo.

Dato che script così grandi non possono nemmeno essere aperti in SQL Server Management Studio, io uso sqlcmd o osql

2
Carol Baker West

Come menzionato @mrdenny -

  1. eseguire prima lo script delle tabelle con tutti gli indici, gli FK, ecc. e creare tabelle vuote nel database di destinazione.

Invece di utilizzare SSIS, utilizzare BCP per inserire dati

  1. bcp i dati usando lo script di seguito. imposta SSMS in modalità testo e copia l'output generato dallo script seguente in un file 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)
    
  2. Esegui il file bat che genererà i file .dat nella cartella che hai specificato.

  3. Esegui sotto lo script sul

    --- 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) 
    
  4. Eseguire l'output utilizzando SSMS per reinserire i dati nelle tabelle.

Questo è un metodo bcp molto veloce in quanto utilizza la modalità nativa.

1
Kin Shah