web-dev-qa-db-ja.com

別のSQL2008データベースへのテーブルの移動(インデックス、トリガーなどを含む)

大量(数百万行)のテーブル全体(100以上)を1つのSQL2008データベースから別のデータベースに移動する必要があります。

元々はインポート/エクスポートウィザードを使用したばかりですが、すべての宛先テーブルに主キーと外部キー、インデックス、制約、トリガーなどがありませんでした(ID列もプレーンINTに変換されましたが、ウィザード。)

これを行う正しい方法は何ですか?

これがいくつかのテーブルである場合、ソースに戻り、テーブル定義(すべてのインデックスなどを含む)をスクリプト化し、宛先でスクリプトのインデックス作成部分を実行します。しかし、非常に多くのテーブルがあるため、これは非現実的です。

データがそれほど多くない場合は、[スクリプトの作成...]ウィザードを使用して、データを含むソースをスクリプト化できますが、72m行のスクリプトは良い考えではないようです。

16
BradC

実際には、インポートウィザードと組み合わせて多くの手動スクリプトを使用してそれを行いましたが、今朝、私は Tibor Karasziのブログ記事 の厚意により、より良い答えを見つけました。

ここでの不満の一部は、SQL 2000「DTSインポート/エクスポートウィザード」が「オブジェクトとデータのコピー」を選択することで実際にこれをほぼ簡単にすることでした。

DTS Import Wizard

この3番目のオプションは、インデックス/トリガーなどを含める機能を含むものです。

Advanced Options

このオプションは[〜#〜]削除されました[〜#〜]SQL 2005/2008からインポートウィザード。どうして?わからない:

2008 Import Wizard

2005/2008では、BIDSでSSISパッケージを手動で作成し、同じオプションをすべて含む SQL Serverオブジェクトの転送タスク を使用する必要があるようです。これらは2000ウィザードに含まれていました。

SSIS Transfer SQL Server Objects Task

9
BradC

テーブルをスクリプト化し、SSISを使用してデータを転送することは、データを新しいデータベースに移動する最も信頼性が高く効果的な方法です。

14
mrdenny

テーブルをスクリプト化するか、比較ツール(Red Gateなど)を使用してターゲットデータベースにテーブルを生成することを検討します。インデックスや制約はまだありません。

次に、同じサーバーに別の名前でデータベースを復元して、

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

..各テーブル、必要に応じてSET IDENTITY INSERT ON

次に、データを読み込んだ後にインデックスと制約を追加します。

それは、SSIS(mrdennyの答え)の快適さのレベル、または生のSQLを好むかどうかによって異なります。

8
gbn

デニー氏の答えに追加します。テーブルスキーマをスクリプトで作成し、BCPを使用してデータを移動します。 SSISに慣れていない場合は、BCPとバッチを使用するのが簡単です。数百万行の場合、BCP(一括挿入)に勝るものはありません。

6
Marian

私はSSISに完全に不快な人です。

ソーステーブルにID列がない場合

  1. ターゲットサーバーに空のデータベースを作成する
  2. ターゲットサーバー上のソースサーバーへのリンクサーバーを作成する
  3. ソースデータベースで以下のスクリプトを実行して、select * into ...ステートメントを生成します。
  4. ターゲットデータベースから生成されたスクリプトを実行する
  5. ソースデータベースのスクリプトの主キー、インデックス、トリガー、関数、およびプロシージャ
  6. 生成されたスクリプトによってこれらのオブジェクトを作成します

今すぐT-SQLは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

これは、コピーするテーブルごとに次のような行を生成します

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

テーブルにID列が含まれている場合は、IDプロパティと主キーを含むテーブルをスクリプト化します。

この場合、リンクサーバーを使用して...に挿入...を使用しません。これは、バルクテクニックではないためです。 [this SO question 1 )のようないくつかのPowerShellスクリプトで作業していますが、まだエラー処理に取り組んでいます。本当に大きなテーブルはメモリ不足の原因になる可能性がありますSQLBulkCopyを介してデータベースに送信される前に、テーブル全体がメモリに読み込まれると、エラーが発生します。

インデックスの再作成などは、上記の場合と同様です。今回は、主キーの再作成をスキップできます。

4
bernd_k

データベーススキーマとデータを比較し、最初にblankデータベーススキーマを元のデータベースと同期する比較ツールを使用して、すべてのテーブルを作成できます。

次に、元のデータベースのデータを新しいデータベースと同期し(すべてのテーブルは存在しますが、すべて空です)、レコードをテーブルに挿入します

ApexSQL DiffApexSQL Data Diff を使用していますが、他にも同様のツールがあります。

このプロセスの良いところは、何百万もの行に対して非常に苦痛になる可能性があるため、ツールを使用して実際にデータベースを同期する必要がないことです。

単にINSERT INTO SQLスクリプトを作成して(数ギグであっても驚かないでください)、それを実行できます。

SQL Server Management Studioで大きなスクリプトを開くことさえできないので、私は sqlcmd または osql を使用します

2

@mrdennyが述べたように-

  1. 最初にすべてのインデックス、FKなどでテーブルをスクリプト化し、宛先データベースに空のテーブルを作成します。

SSISを使用する代わりに、BCPを使用してデータを挿入する

  1. 以下のスクリプトを使用してデータをbcpします。 SSMSをテキストモードに設定し、以下のスクリプトによって生成された出力を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. 指定したフォルダーに.datファイルを生成するbatファイルを実行します。

  3. 以下でスクリプトを実行します

    --- 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. SSMSを使用して出力を実行し、データをテーブルに挿入します。

これはネイティブモードを使用するため、非常に高速なbcpメソッドです。

1
Kin Shah