问题 如何使用insert语句将数百万个不同RDBMS的数据插入到SQL Server数据库中?


我的SQL Server中有两个数据库,每个数据库包含1个单表。

我有2个数据库,如下所示:

1)Db1(MySQL)

2)Db2(Oracle)

现在我要做的是用MySQL中的Db1数据填充SQL Server db1的数据库表,如下所示:

Insert into Table1 select * from Table1

从Table1中选择*(Mysql Db1) - 来自Mysql数据库的数据

插入Table1(Sql server Db1) - 插入来自Mysql的数据   考虑相同架构的数据库

我不想使用sqlbulk copy,因为我不想通过块数据插入块。我想在1中插入所有数据,考虑数百万个数据,因为我的操作不仅限于在数据库中插入记录。因此,用户必须等待很长时间,比如数百万的数据在数据库中通过块插入块,然后再次进行我的进一步操作,这也是长时间运行的操作。

因此,如果我将此进程加速,那么考虑到所有记录都在我的本地sql server实例中,我可以加快我的第二次操作。

这可能在C#应用程序中实现吗?

更新: 我研究了关于Linked server的问题 @GorDon Linoff 建议我链接服务器可用于实现这种情况,但根据我的研究,似乎我不能通过代码创建链接服务器。

我希望借助它来做到这一点 ado.net

这就是我想要做的事情:

考虑我有2个不同的客户端RDBMS,2个数据库和客户端内部的一些表。

所以数据库是这样的:

Sql Server :

Db1

Order
Id      Amount
1       100
2       200
3       300
4       400


Mysql or Oracle :

Db1:

Order
Id      Amount
1       1000
2       2000
3       3000
4       400

现在我想比较从源(SQL Server)到目标数据库(MySQL或Oracle)的Amount列。

我将使用这两个不同的RDBMS数据库表来比较Amount列。

在C#中我能做的就像在我的块中通过块记录获取块 数据表(在内存中) 然后将这些记录与代码的帮助进行比较,但考虑到数百万条记录,这需要花费大量时间。

所以我想做一些比这更好的事情。

因此,我想我在2个数据库中的本地SQL服务器实例中显示这2个RDBMS记录,然后根据Id创建连接此2个表的连接查询,然后利用DBMS处理功能,可以有效地比较这数百万个记录。

这样的查询有效地比较了数百万条记录:

select SqlServer.Id,Mysql.Id,SqlServer.Amount,Mysql.Amount from SqlServerDb.dbo.Order as SqlServer
Left join MysqlDb.dbo.Order as Mysql on SqlServer.Id=Mysql.Id
where SqlServer.Amount != Mysql.Amount

当我在我的本地服务器实例中使用数据库:SqlServerDb和MysqlDb这两个不同的RDBMS数据时,上面的查询有效,这将获取以下数量不匹配的记录:

所以我试图将这些记录从源(Sql server Db)获取到其Amount列值不匹配的MySQL。

预期产出: 

Id      Amount
1       1000
2       2000
3       3000

那么有什么方法可以实现这种情况?


11695
2017-12-14 13:12


起源

使用链接服务器。 - Gordon Linoff
@GordonLinoff我在项目中提到的链接服务器是否可行? - Learning-Overthinker-Confused
应该可以使用链接服务器。 - Gordon Linoff
@GordonLinoff非常感谢你的建议,但看起来链接服务器只适用于Sql服务器,但如果我将我的数据库安装在Mysql或Oracle中,它将无法工作。 - Learning-Overthinker-Confused
我不同意你的看法,即通过数据库链接将数据从oracle拖入sqlserver,将比每个数据库的专用批量导出/导入例程更快 - Caius Jard


答案:


SELECT 一边,创造一个 .csv 文件(制表符分隔)使用 SELECT ... INTO OUTFILE ...

INSERT方,使用 LOAD DATA INFILE ... (或任何目标机器语法)。

一次完成所有操作可能比分块更容易编码,并且可能(或可能不)更快地运行。


4
2017-12-16 19:49



因此,如果我的表包含数百万条记录,那么这个选择输出文件将与此插入加载数据文件一起快速? - Learning-Overthinker-Confused
我已经更新了我的问题,以显示我正在尝试做什么 - Learning-Overthinker-Confused
@Rick James,这是个好主意,但有些时候它不能正常工作 - er.irfankhan11
@Irfan - “不能正常工作” - 你能详细说明吗? - Rick James
我已经使用这种方法在块中执行此操作。但是,如果您使用DataReader读取源并将读取器传递给SqlBulkCopy,那么您无需担心数据的大小。我已经使用读者方法来加载数亿行。使用块方法,您需要仔细规划块的大小,否则您的.net进程将咀嚼大量内存。使用数据阅读器,我不必担心任何问题。 - suresubs


SqlBulkCopy 可以接受a DataTable 或者a System.Data.IDataReader 作为它的输入。

使用您的查询来读取源数据库,设置ADO.Net DataReader 在源MySQL或Oracle DB上并将读者传递给 WriteToServer() 的方法 SqlBulkCopy

这可以无限制地复制几乎任意数量的行。我使用数据读取器方法复制了数亿行。


2
2017-12-21 04:29



但每次我必须执行此导入过程,以便在我们不想做的2个不同的rdbms数据库表之间进行比较。除此之外,还有其他更好的方法吗? - Learning-Overthinker-Confused
它非常快。它通过块方法消除了块。我相信你的问题是加载到sql server中的chunk-by-chunk。如果没有将数据实际导入到同一个sql server实例中,则无法有效地进行比较。我们在.Net中构建了额外的框架支持,以实现这一点。您可以使用global temp ## table轻松加载和比较,因此除了设置sql之外,您不需要任何准备工作。我们已经参数化了这个过程,所以我们只需要提供源sql,## temp表定义和比较查询。 - suresubs
您是否认为像hadoop这样的大数据可以帮助这个过程或链接服务器,正如一些用户在这个答案中提到的那样? - Learning-Overthinker-Confused
任何hadoop类型的解决方案都需要更多的努力并设置其他软件。我上面提出的建议不需要任何额外的设置。特别是如果您使用全局临时表(##)作为临时表,您甚至不需要通过DBA。我们在企业环境中完成了这项工作,其中包含许多关于创建新表,链接服务器和所有表的控件。您可以通过编写简单的C#代码来完成所有这些工作。加载速度仅受源DB提供数据的能力的限制。 SQLBulkCopy非常快。任何增量比较也可以很容易地设计到这里。 - suresubs
为了帮助我而付出了努力,但是请你详细说明你的最后一句话“任何delta比较也可以很容易地设计到这个” - Learning-Overthinker-Confused


如何在远程数据库中添加更改日期。

然后你可以获得自上次同步以来已经改变的所有行并且只是比较那些?


1
2017-12-18 13:29



很抱歉,这将通过我们的应用程序完成,我们希望存储此类记录以生成报告并进行一些其他操作。 - Learning-Overthinker-Confused


首先不要使用链接服务器。它很诱人,但它会带来更多的麻烦。像更新和插入一样,将获取所有目标数据库到源数据库并执行插入/更新并将所有数据发布到目标服务器。

据我所知,您正在尝试将已更改的数据复制到目标系统中以获取某些内容。

我建议在源表上使用timestamp列。当源表上的任何更改时间戳列由sql server更新时。

在目标上,获取最大ID和最大时间戳。最多两个查询

在源,行在哪里 source.ID <= target.MaxID && source.timestamp >= target.MaxTimeTamp 是的,是上次同步后更改的行(需要更新)。和行在哪里 source.ID > target.MaxID 是的,是上次同步后插入的行。

现在您不必比较两个世界,您只需获得所有更新和插入。


1
2017-12-19 10:57



对不起,这个过程就像1个数据库从1个系统(假设Sql服务器)迁移到另一个(Mysql)或者可能是Sql Server(Server1)到Sql server(服务器在另一个位置)时可能会出现一些数据问题的变化,如as我已经在我的示例记录中向您展示了3条记录的Amount列如何从源(Sql server)更改为目标(Mysql)。所以现在在我的应用程序的帮助下,我想存储并找出这种类型的有问题的记录,所以有一些操作,如报告和其他东西 - Learning-Overthinker-Confused
此外,这里有3个数据库,2个客户端数据库(如oracle,Sql服务器,Mysql等任何Rdbms),我想要比较1个我的应用程序数据库(严格的Sql Server),我想在这个数据库中存储有问题的记录用于显示我的申请报告 - Learning-Overthinker-Confused
我的观点是,如果可以保证时间戳列(假设复制为二进制值),则无需进行比较。只是比较ID和时间戳列可以为您提供任何已更改的记录,并且最好不依赖于您在目标上运行的数据库。您的要求是通过比较它们来查找修改后的记录。我只是试图在没有比较的情况下获得相同的结果。当我们向客户发布批量数据时,我们正在使用此解决方案。他们接收插入/更新的数据,并更新他们的数据库。 - edokan
但那些将是客户端数据库,我们无法说出你所建议的内容。因此我们必须找到一些其他方法来比较2个不同的rdbms表。我们正在考虑使用hadoop hdfs和map reduce但是这里的问题是没有在2 hdfs文件之间创建连接的方法,比如我们如何链接rdbms中的2个表虽然有一些像hive这样的工具允许我们编写sql查询但是他们不提供apis来按需运行这个比较 - Learning-Overthinker-Confused


您需要使用ODBC和正确的驱动程序创建链接服务器连接,之后您可以使用openquery执行查询。

看一下openquery:

https://msdn.microsoft.com/en-us/library/ms188427(v=sql.120).aspx


1
2017-12-19 11:36



但我已经提到过链接服务器,我可以通过代码创建链接服务器。这可能吗? - Learning-Overthinker-Confused
我想你可以使用sp_addlinkedserver程序(docs.microsoft.com/en-us/sql/relational-databases/...)创建链接服务器,在这个站点中你有一个工作示例 mssqltips.com/sqlservertip/4570/...。 - arturios
这个链接的服务器将保留在MSSQL服务器上,如果您在运行查询后不再需要它们,则需要删除它们。 - arturios
但是你认为Linkedserver会帮助我实现我预期的输出,考虑到2个不同的RDBMS数据库表比较吗? - Learning-Overthinker-Confused
是的,它将作为普通表工作,您可以插入,更新,删除和所有必要的操作。我以前做过那个。但要从其他数据库访问表,您将始终需要使用openquery,如SELECT * FROM OPENQUERY(linkedserver_name,“SELECT * FROM TABLE1”) - arturios


是的,SQL Server在处理集合时非常有效,所以让我们继续使用它。

简而言之,我正在投球

  1. 将数据从源加载到目标数据库上的临时表(staging table = table,以暂时保存源表中的原始数据,与源表相同的结构...添加跟踪列以进行品味)。这将由您的C#代码完成...从source_table选择DataTable然后选择SqlBulkCopy到登台表。

  2. 在目标数据库上有一个存储过程,以协调目标表和登台表之间的数据。您的C#代码调用存储的proc。

鉴于您正在谈论数百万行,另一件可以使事情更快的事情是在插入表之前删除登台表上的索引并在插入之后和执行任何选择之前重新创建索引。


1
2017-12-23 02:21



但是你不认为这是一个额外的步骤(开销),首先我必须通过块数据提供块来进行sql批量复制,然后存储在sql server staging表中,用于2个不同的rdbms数据库表,以便进行比较 - Learning-Overthinker-Confused
是的数百/几千行...不是数百万。宽松的比喻......如果我把一副牌放在你的厨房桌子和你起居室的另一个牌组上,那么你就可以从另一个牌组中找到相应的牌。如果你将整个甲板从厨房带到起居室然后在同一个地方有两个甲板时找到匹配,你会来回跑52次会更快吗? - Goose
好的,我同意,但我不明白你的第二点。你能告诉我更多关于这一点 - Learning-Overthinker-Confused
第二点是一个存储过程,它将包含您的查询以及将修改数据的必要更新语句。 - Goose