【问题标题】:What is the most efficient way to copy UniDataSet to SQL Server?将 UniDataSet 复制到 SQL Server 的最有效方法是什么?
【发布时间】:2015-06-12 19:31:28
【问题描述】:

我有一个 U2/UniVerse 数据库,需要将一个表中的数据复制到 SQL Server 表中。有问题的表有大约 600,000 行和不到 200 列。我没有创建表,也无法更改它。

对于其他表,我一次循环通过UniDataSet 一条记录并将其添加到DataTable,然后使用SqlBulkCopy 将记录复制到SQL Server。这很好用,但是在创建DataTable 时,我似乎内存不足。

DataTable dt = new DataTable("myTempTable");
dt.Columns.Add("FirstColumn", typeof(string));
dt.Columns.Add("SecondColumn", typeof(string));
... //adding a bunch more columns here
dt.Columns.Add("LastColumn", typeof(string));

U2Connection con = GetU2Con();
UniSession us1 = con.UniSession;
UniSelectList s1 = us1.CreateUniSelectList(0);
UniFile f1 = us1.CreateUniFile("MyU2TableName")
s1.Select(f1);

UniDataSet uSet = f1.ReadRecords(s1.ReadListAsStringArray());

foreach (UniRecord uItem in uSet)
{
    List<String> record = new List<String>(uItem.Record.ToString().Split(new string[] { "þ" }, StringSplitOptions.None));

    DataRow row = dt.NewRow();

    row[0] = uItem.RecordID;
    row[1] = record[0];
    row[2] = record[1];
    ... //add the rest of the record
    row[50] = record[49]

    dt.Rows.Add(row);
}

con.Close();

这样就可以将UniDataSet 中的记录复制到DataTable 中。然后,我把SqlBulkCopyDataTable变成了一个SQL表:

string SQLcon = GetSQLCon();

using (SqlBulkCopy sbc = new SqlBulkCopy(SQLcon))
{
    sbc.DestinationTableName = "dbo.MySQLTableName";
    sbc.BulkCopyTimeout = 0;
    sbc.BatchSize = 1000; //I've tried anywhere from 50 to 50000

    try
    {
        sbc.WriteToServer(dt);
    }
    catch
    {
        Console.WriteLine(ex.Message);
    }
}

这对于我的具有 50,000 左右行的 U2 表来说效果很好,但是当表具有 500,000 行时,它基本上会使调试器(VS Express 2012)崩溃。我正在执行此操作的 PC 是具有 4GB 内存的 Windows 7 x64。 VS 进程在崩溃之前看起来最多使用 3.5GB RAM。

我希望有一种方法可以使用 SqlBulkCopy 将 UniDataSet 写入 SQL,但我对 U2 .Net 工具包不太熟悉。

我面临的问题是 UniDataSet 记录是多值的,我需要先将它们分开,然后才能将它们写入 SQL。

谢谢!

【问题讨论】:

    标签: c# sql-server u2 u2netdk rocket-u2


    【解决方案1】:

    DataTable 在插入数据库之前,它在内存中变得太大了。 为什么不拆分批量插入操作?例如读取前 50.000 个结果并插入到 Sql server 数据库,清除 DataTable Memory 并重新开始接下来的 50.000 行。

    if (dt.Rows.Count > 50000)
    {
        //do SqlbulkCopy
        dt.Rows.Clear();
    }
    

    【讨论】:

    • 我现在正在尝试类似的事情,我从 UniFile 中删除一半的记录,运行我的其余代码,然后对另一半再次执行此操作。谢谢你的建议..我也打算这样试试。
    • 我接受了这一点,因为它是我解决方案的基础(也是我得到的唯一答案.. :)。我将SqlBulkCopy 移动到ForEach 循环中,并以if (dt.Rows.Count == 300000 || uSet.AfterLast == true) 开头。这会触发 SqlBulkCopy 两次,一次大约是通过 UniDataSet 的一半,最后一次。谢谢!
    【解决方案2】:

    在 U2 Toolkit for .NET v2.1.0 中,我们实现了 Native Access。现在您可以直接从 UniData/UniVerse 文件创建 DataSet/DataTable。您也可以指定 WHERE 和 SORT 子句。您将看到性能改进,因为它不会花费太多的 Server Trip 来获取 ID。例如,如果您有 1000 个记录 ID,它将进行 1000 次 Server Trip。然而,如果您使用 Native Access,它将进行一次 Server Trip。

    请下载 U2 Toolkit for .NET v2.2.0 Hot Fix 1 并尝试以下代码。欲了解更多信息,请联系 u2askus@rocketsoftware.com。

                U2Connection con = GetU2Con();
                U2Command cmd = lConn.CreateCommand();
                cmd.CommandText = string.Format("Action=Select;File=MyU2TableName;Attributes=MyID,FirstColumn,SecondColumn,LastColumn;Where=MyID>0;Sort=MyID");
                U2DataAdapter da = new U2DataAdapter(cmd);
                DataSet ds = new DataSet();
                da.Fill(ds);
                DataTable dt = ds.Tables[0]; 
    

    【讨论】:

    • 拉詹,这太棒了!我会试一试。我将如何修改您的 Select 语句以包含给定 U2 表中的所有属性?
    • 不建议这样做。但是如果你的字典是干净的,你可以试试下面的语法。 cmd.CommandText = string.Format("Action=Select;File=MyU2TableName");我们正在字典中查找“@ID”以外的 ID。例如,序数/位置 0 可以有 @ID 和 MYID。在此处查看更多示例代码:C:\Program Files (x86)\Rocket Software\U2 Toolkit for .NET\U2 Database Provider\samples\C#\UniData\NativeAccess。问候,拉詹
    • 当遇到da.Fill(ds) 时,我收到错误“对象引用未设置为对象的实例”。查看示例代码时,我看到连接字符串使用RpcServiceType=udcs,但我的代码使用了uvcs。使用udcs时,无法连接到服务器。
    • 是的,“uvcs”适用于 UniVerse。请问您能做到以下几点吗? 1. 联系 Rocket U2 支持并创建问题 2. 发送日志文件 (u2askus@rocketsoftware.com) (Attn: Rajan Kumar) 3. 创建日志文件:github.com/RocketSoftware/multivalue-lab/tree/master/U2/Demos/…
    猜你喜欢
    • 2011-04-14
    • 2011-06-04
    • 2020-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-23
    • 1970-01-01
    • 2010-10-16
    相关资源
    最近更新 更多