有没有办法优化从 Oracle 到 SQL 服务器的数据迁移并减少花费的时间?

Is there a way to optimize data migration from Oracle to SQL Server and reduce the time spent?

我正在使用 SSMS 中的 T-SQL 脚本将数据从 Oracle(12c 不可插拔)数据库迁移到 SQL 服务器 (2012),并将 Oracle 数据库设置为链接服务器.模式已经同步,所以唯一剩下的就是数据。我面临的问题是迁移所花费的时间及其消耗的内存量。

当 运行 我的脚本时,它需要很长时间,最初我 运行 在迁移完整 tables 时进入 SQL 服务器-服务器上的内存问题,所以我决定将 table 的迁移一次拆分为 1,000,000 行的块。但是,我的代码中似乎有一个 "memory leak",因为查询消耗的内存随着每次迭代而增加,并且查询花费了很长时间。

编辑:我删除了 MS SQL 服务器数据库中的索引。

我的脚本有效,但是当迁移较大的 tables 时,查询将关闭可用内存并且迁移开始时每 1 行大约需要 5 分钟(并且随着每次迭代)。当然,时间也取决于 table 等中的行数。

数据统计: * 桌子:~1600 * 总行数:~1 Bill。 (最大的 table 是 300 行)

USE INFODBA
GO

SET NOCOUNT ON

DECLARE @start BIGINT
DECLARE @end BIGINT
DECLARE @maxrows BIGINT
DECLARE @step BIGINT
DECLARE @sqlstr NVARCHAR(4000)
DECLARE @table_name VARCHAR(255)
DECLARE @counter INT
DECLARE @time TIME
DECLARE @error NVARCHAR(4000)

-- Iterates in @step rows at a time
SET @step = 1000000;
SET @start = 0;
SET @end = @start + @step;
SET @counter = 1;

SET @table_name = 'sourceTable'
PRINT @table_name;

-- GET exact rowcount of Oracle table
SELECT @maxrows = NUM_ROWS FROM OPENQUERY(ORACLETC, 'SELECT COUNT(*) AS NUM_ROWS FROM sourceTable')

WHILE @start < @maxrows
BEGIN
    SELECT @time = CONVERT (time, CURRENT_TIMESTAMP)

    SET @sqlstr = 'INSERT INTO targetTable SELECT * FROM OPENQUERY(ORACLETC,''SELECT COL1,COL2,COL3,COL4 FROM sourceTable'
    SET @sqlstr = @sqlstr + ' OFFSET ' + CAST(@start AS NVARCHAR(255)) + ' ROWS FETCH NEXT ' + CAST(@step AS NVARCHAR(255)) + ' ROWS ONLY'') AS ROWSET_1';

    -- Print output immediatly to capture progress
    PRINT 'Iteration;' + CAST(@counter AS VARCHAR(255)) + ';Time;' + CAST(@time AS VARCHAR(255)) + ';Start;' + CAST(@start AS VARCHAR(255)) + ';End;' + CAST(@end AS VARCHAR(255)) + ';MAX;' + CAST(@maxrows AS VARCHAR(255)) + ';Query;' + @sqlstr
    RAISERROR (N'', 0, 1) WITH NOWAIT

    -- Start the migration query and catch error messages
    BEGIN TRY
        BEGIN TRANSACTION;
            EXEC dbo.sp_executesql @sqlstr
        COMMIT;
    END TRY
    BEGIN CATCH
        SELECT @error = ERROR_MESSAGE();
        PRINT 'ERROR on iteration: ' + CAST(@counter AS VARCHAR(255)) + ' with query: ' + @sqlstr + ' - Error: ' + @error
        SELECT ERROR_MESSAGE() AS ErrorMessage;
        RETURN
    END CATCH

    SET @counter += 1
    SET @start = @end
    SET @end += @step
END

此脚本将以 1 行为一组迁移数据,但现在看来,根据执行计划,oracle 查询似乎花费了最多的时间(大约 80%)。此外,尽管我尝试使用 "begin transaction" 和 "commit"(可能有更好的使用方法),但如前所述,脚本增加了每次迭代的内存占用(大部分内存在提交时释放,但在后台缓慢增加)

有多种方法。

  1. 删除 SQL 服务器上的索引 table 您将数据导入并在导入后重新创建它们。

  2. 单独导出、传输和加载。这意味着将 Oracle 服务器上的数据提取为纯文本文件,然后通过 ftp 将它们传输到 SQL 服务器机器,然后将它们加载到 SQL 服务器。

  3. (最有效的方法)使用 MS SQL 服务器批量加载:https://docs.microsoft.com/en-us/sql/relational-databases/import-export/bulk-import-and-export-of-data-sql-server?view=sql-server-2017 在这种情况下,您的 1m 记录将不会通过整个数据库进行处理,而是直接写入数据库文件,速度要快得多。

弗拉德的回答是正确的;您当前的查询包括动态 SQL、WHILE 循环和 OPENQUERY,所有这些通常都是性能消耗者。使用批量加载(即 BCP)或 SSIS 包导入平面文件应该会给您带来更好的结果。