1

我有一个程序可以将数据从服务器数据库下载到客户端数据库。服务器数据库最近不断增长。

在该程序中,有一个选项可以选择下载所有数据或下载特定时间段的数据(可以从今天开始选择向后的日期)。如果用户选择全部,我编写程序来截断客户端数据库表并使用批量复制插入所有数据。那部分没问题。

但问题是当用户选择特定时间段(每个重新编码已创建数据时间)时,程序必须比较两个表并将重新编码(服务器数据)划分为两个表。一是不存在数据,二是不存在数据。我要做的是,不是现有数据直接插入客户端数据库(我正在使用批量插入)和现有数据使用批量复制插入临时表,并在使用上述临时表更新客户端表之后。划分服务器表时出现我的实际问题。我就是这样做的

 updateTable = (From c In dt_from_server.AsEnumerable() 
                Join o In Dt_from_client.AsEnumerable() 
                On c.Field(Of String)("BARCODE").Trim() Equals o.Field(Of String)("BARCODE").Trim() 
                And c.Field(Of String)("ITEM_CODE").Trim() Equals o.Field(Of String)("ITEM_CODE").Trim() 
                Select c).CopyToDataTable()

 insertTable = dt_server.AsEnumerable()
    .Except(updateTable.AsEnumerable(), DataRowComparer.Default)
    .CopyToDataTable()

(服务器表中通常有超过 1M 的重新编码)

当有超过 100 万次重新编码时,更新部分需要 10 分钟的可接受时间(是的,它从 Ram 占用 5GB 空间 - 在这种情况下,考虑性能时可以)但插入部分接缝需要几天时间,只是为了评估 insertTable(datatable) . 这就是问题所在。
AsEnumerable().Except()部分需要很长时间,我找不到加速这个过程的解决方案。我不确定我是否正确解释了这一点。任何人都可以给我一些建议吗?

4

1 回答 1

1

由于您已经评论过 dt_from_server并且dt_server 实际上是相同的,因此DataTable您不需要将 all 的所有值DataRows相互比较,这就是这样DataRowComparer.Default做的。您可以Except在没有第二个参数的情况下使用比较器,然后只比较参考,这要快得多。

您也不需要两个在内存CopyToDataTable中创建两个额外的大DataTables的,一个接一个地处理行。

这是使用 Linq 的左外连接的另一种方法,它更有效:

Dim query = from rServ in dt_from_server.AsEnumerable()
            group join rClient in Dt_from_client.AsEnumerable()
            On New With{
                Key .BarCode = rServ.Field(Of String)("BARCODE").Trim(),
                Key .ItemCode = rServ.Field(Of String)("ITEM_CODE").Trim()
            } Equals New With{
                Key .BarCode = rClient.Field(Of String)("BARCODE").Trim(),
                Key .ItemCode = rClient.Field(Of String)("ITEM_CODE").Trim()
            }   into Group
            From client In Group.DefaultIfEmpty()  
            Select new With { .ServerRow = rServ, .InsertRow = client is Nothing }

Dim insertOrUpdateRows = query.ToLookup(Function(x) x.InsertRow, Function(x) x.ServerRow)
Dim insertRows = insertOrUpdateRows(true).CopyToDataTable()  'CopyToDataTable redundant if you process rows immediately now' 
Dim updateRows = insertOrUpdateRows(false).CopyToDataTable() 'CopyToDataTable redundant if you process rows immediately now' 

但一般来说,最可扩展和最有效的方法是不要一次将所有内容加载到内存中然后处理所有内容,而是使用数据库分页(或存储过程)仅处理内存中的部分内容,否则很可能你OutOfMemoryException迟早会遇到的。


C# 按要求:

var query = from rServ in dt_from_server.AsEnumerable()
            join rClient in Dt_from_client.AsEnumerable()
            on new { BarCode = rServ.Field<string>("BARCODE").Trim(), ItemCode = rServ.Field<string>("ITEM_CODE").Trim() }
            equals new { BarCode = rClient.Field<string>("BARCODE").Trim(), ItemCode = rClient.Field<string>("ITEM_CODE").Trim() } 
            into clientGroup
            from client in clientGroup.DefaultIfEmpty()
            select new { ServerRow = rServ, InsertRow = client == null };

var insertOrUpdateRows = query.ToLookup(x => x.InsertRow, x => x.ServerRow);
var insertRows = insertOrUpdateRows[true].CopyToDataTable();  // CopyToDataTable redundant if you process rows immediately now
var updateRows = insertOrUpdateRows[false].CopyToDataTable(); // CopyToDataTable redundant if you process rows immediately now
于 2017-10-20T08:51:24.913 回答