我们想要在Oracle 11g R2和SQL Server 2014之间快速传输一大批数据,容量超过20TB,拥有数千个表格和数十亿条记录(这是一个为期五年的数据仓库)。
由于我们需要传输的表格和分区数量巨大,约为40k个表格和分区,SSIS并不可行。我们拥有一些营销应用程序、活动管理器、挖掘模型等,它们运行在不同的架构中。其中一些每天会创建150个新表格,而“删除表格率”约为100个/天。这些架构正是我们无法使用SSIS的原因,因为我们需要传输它们。
因此,我们开发了一个C# 2013的应用程序,并使用了.Net 4.5.1,它是多线程的。每个线程读取Oracle中的一个表格/分区,在SQL Server中创建相同的表格/分区模式,然后继续从Oracle中选择数据,并批量插入到SQL Server中,最后创建所有未决的约束和索引。
我们面临的主要问题之一是传输速度。与SSIS的性能相比,在传输包含30个分区的1个事实表(每月事实表,每日分区,每个分区约有3000万条记录,60+列)时,我们发现该应用程序从未使用全网络速度,而SSIS使用了100%的速度(我们使用Attunity SSIS Connectors for Oracle...其中可能有一个传输速度优势,但我不确定),如果可以的话,我们希望改善这一点。
以下是负责写入的代码块。
有没有关于在SQL Server或者C#应用程序中的SQLBulkCopy对象可以测试或配置的任何建议(代码中注释的部分来自之前已测试过的选项)?
PS:以下是我们环境的一些信息...
Oracle服务器客户端上行带宽为2 Gbps,SQL Server下行带宽为1 Gbps,Oracle是一个32核系统,我们测试的SQL Server是一个16核Win Server 2012 R2系统... SSIS网络传输速度为1 Gbps全速,C#应用程序的网络传输速度约为70 Mbps,使用16个线程...
编辑以提供有关传输速度的更多信息:
我们应用程序测试的更多信息:
2个线程 = 15-25 Mbps
4个线程 = 30-40 Mbps
8个线程 = 60-65 Mbps
16个线程 = 65-70 Mbps
超过16个线程(每个系统内核的1个应用程序线程)会将性能降至30-50 Mbps。
我们的SAN非常适合高I/O计数的速度超过500 MB/s
我们最好的批处理大小时间是基于每批次2500-5000行的值获得的(使用8-16个线程,在5分钟内处理了大约1500万行)
现在我们的应用程序将数据从Oracle中的一个表/分区传输到SQL Server中的另一个表/分区...我们有一些非分区表,其中包含100多万行数据...对于这些表,我们测试了多个线程读取同一张表...我们成功地完成了读取过程,但在批量插入数据时失败。
每个线程对一个数字列执行MOD操作以读取同一张表。
由于我们需要传输的表格和分区数量巨大,约为40k个表格和分区,SSIS并不可行。我们拥有一些营销应用程序、活动管理器、挖掘模型等,它们运行在不同的架构中。其中一些每天会创建150个新表格,而“删除表格率”约为100个/天。这些架构正是我们无法使用SSIS的原因,因为我们需要传输它们。
因此,我们开发了一个C# 2013的应用程序,并使用了.Net 4.5.1,它是多线程的。每个线程读取Oracle中的一个表格/分区,在SQL Server中创建相同的表格/分区模式,然后继续从Oracle中选择数据,并批量插入到SQL Server中,最后创建所有未决的约束和索引。
我们面临的主要问题之一是传输速度。与SSIS的性能相比,在传输包含30个分区的1个事实表(每月事实表,每日分区,每个分区约有3000万条记录,60+列)时,我们发现该应用程序从未使用全网络速度,而SSIS使用了100%的速度(我们使用Attunity SSIS Connectors for Oracle...其中可能有一个传输速度优势,但我不确定),如果可以的话,我们希望改善这一点。
以下是负责写入的代码块。
//private static async Task saveDataBlock(IDataReader reader, string destinationTable, int batchSize)
private static void saveDataBlock(IDataReader reader, string destinationTable, int batchSize)
{
//System.Data.SqlClient.SqlBulkCopy bc = new System.Data.SqlClient.SqlBulkCopy(getConnString(destinationCS));
//System.Data.SqlClient.SqlBulkCopy bc = new System.Data.SqlClient.SqlBulkCopy(getConnString(destinationCS), System.Data.SqlClient.SqlBulkCopyOptions.KeepIdentity & System.Data.SqlClient.SqlBulkCopyOptions.KeepNulls & System.Data.SqlClient.SqlBulkCopyOptions.TableLock);
using (SqlBulkCopy bc = new SqlBulkCopy(getConnString(destinationCS)))
{
bc.BulkCopyTimeout = 0;
bc.DestinationTableName = destinationTable;
bc.BatchSize = batchSize; //2500,5000,10000.. best so far, 5000
//bc.BatchSize = 0;
bc.NotifyAfter = batchSize;
bc.SqlRowsCopied += new SqlRowsCopiedEventHandler(s_SqlRowsCopied);
//bc.EnableStreaming = true;
bc.ColumnMappings.Clear();
for (int i = 0; i < reader.FieldCount; i++)
{
bc.ColumnMappings.Add(reader.GetName(i), reader.GetName(i));
}
bc.WriteToServer(reader);
//await bc.WriteToServerAsync(reader);
//bc.Close();
}
//System.Data.SqlClient.SqlBulkCopy bc = new System.Data.SqlClient.SqlBulkCopy(getConnString(destinationCS), SqlBulkCopyOptions.UseInternalTransaction);
}
有没有关于在SQL Server或者C#应用程序中的SQLBulkCopy对象可以测试或配置的任何建议(代码中注释的部分来自之前已测试过的选项)?
PS:以下是我们环境的一些信息...
Oracle服务器客户端上行带宽为2 Gbps,SQL Server下行带宽为1 Gbps,Oracle是一个32核系统,我们测试的SQL Server是一个16核Win Server 2012 R2系统... SSIS网络传输速度为1 Gbps全速,C#应用程序的网络传输速度约为70 Mbps,使用16个线程...
编辑以提供有关传输速度的更多信息:
我们应用程序测试的更多信息:
2个线程 = 15-25 Mbps
4个线程 = 30-40 Mbps
8个线程 = 60-65 Mbps
16个线程 = 65-70 Mbps
超过16个线程(每个系统内核的1个应用程序线程)会将性能降至30-50 Mbps。
我们的SAN非常适合高I/O计数的速度超过500 MB/s
我们最好的批处理大小时间是基于每批次2500-5000行的值获得的(使用8-16个线程,在5分钟内处理了大约1500万行)
现在我们的应用程序将数据从Oracle中的一个表/分区传输到SQL Server中的另一个表/分区...我们有一些非分区表,其中包含100多万行数据...对于这些表,我们测试了多个线程读取同一张表...我们成功地完成了读取过程,但在批量插入数据时失败。
每个线程对一个数字列执行MOD操作以读取同一张表。
select * from schema.table where MOD(NUMERIC_COLUMN, N) = 0 to N-1
N是我们运行的线程数... 我们尝试重新创建一些 SSIS 行为,以最大化 Oracle/SQL 中的线程使用和数据读取/写入。在 SSIS 中,我们可以在目标地设置每个线程的 LOCK TABLE 选项,并且它可以完美运行。但是,在我们的应用程序中执行此操作时,每个线程在插入期间都会锁定表,最终导致我们的并行设计变成了串行 :( (这不是问题的主要原因,但如果有人对此有建议,我们将不胜感激)
SSIS不是一个选项,因为我们需要传输的表格和分区数量非常庞大
。看起来它与你自己开发的系统相比处理速度还不错。 - billinkc