比较内存中的2个无序记录集

ILo*_*low 10 c# sql linq algorithm ado.net

下面是我的应用程序数据库表,其中包含存储在表中的SQL查询:QueryStorage

Id           Query           ConnectionString       Rdbms
1            select...        Data Source           Sql Server
2            select...        Data Source           Oracle
Run Code Online (Sandbox Code Playgroud)

上表中的SQL查询是通过Web服务更新的,我们不允许在查询之上更新,但我们可以在查询之外添加一些内容,如下所示:

存储在表中的查询: select id as LinkedColumn, Amount as CompareColumn from Source

来自我的c#app的调整查询:select Q.LinkedColumn, Q.CompareColumn from (stored sql query) as Q

我想比较下面的2个无序列表:

Id = 1(Sql server)QueryStorage表记录执行的查询如下所示:

select Id as LinkedColumn,CompareColumn from Source
Run Code Online (Sandbox Code Playgroud)

清单1:

LinkedColumn     CompareColumn
1                100
2                200
3                300
4                400
5                500
6                600
7                700
8                800
9                900
10               1000
Run Code Online (Sandbox Code Playgroud)

Id = 2(Oracle)QueryStorage表记录执行的查询如下所示:

select Id as LinkedColumn,CompareColumn from Target
Run Code Online (Sandbox Code Playgroud)

清单2:

LinkedColumn       CompareColumn
10                 10
9                  20
8                  30
7                  40
6                  50
5                  60
4                  70
3                  80
2                  90
1                  5
Run Code Online (Sandbox Code Playgroud)

我想加入LinkedColumn from source to target然后做比较,CompareColumn哪个应该给我以下输出:

SrcLinkedColumn      SrcCompareColumn     TgtLinkedColumn    TgtCompareColumn
    1                       100           1                  5
    2                       200           2                  90               
Run Code Online (Sandbox Code Playgroud)

逻辑:

var data = (from s in List1.AsEnumerable()
             join t in List2.AsEnumerable() on s.Field<string>("LinkedColumn") equals t.Field<string>("LinkedColumn")
             where s.Field<decimal>("CompareColumn") != t.Field<decimal>("CompareColumn")
                        select new
                        {
                            srcLinkedcol = s.Field<string>("LinkedColumn"),
                            srcCompareCol = s.Field<decimal>("CompareColumn"),
                            tgtLinkedCol = t.Field<string>("LinkedColumn"),
                            tgtCompareCol = t.Field<decimal>("CompareColumn")
                        }).ToList();
Run Code Online (Sandbox Code Playgroud)

从源到目标将有数百万条记录,我想out of memory exception通过将所有数据加载到内存中然后与上面的linq查询进行比较来解决我们现在面临的大问题.

我有两种解决方案,如下所示:

1)打开2个有序数据读取器.

优点:

    - No memory exception
    - Fast as there will be 1 to 1 comparision of LinkedColumn for List1 and 
      List2 records.
Run Code Online (Sandbox Code Playgroud)

缺点:

    - Order by is require on LinkedColumns and as i have no control over 
      query as because it is dumped by webservice in QueryStorage table so 
      user is explicitly require to submit query with order by on 
      LinkedColumn.
    - Wont work if order by on Linkedcolumn is not present.
    - Order by query have performance overhead so because of this user may not include order by on LinkedColumn in query.                               
Run Code Online (Sandbox Code Playgroud)

2)通过调整查询和添加来比较块的大块记录OffSet and FetchRowNext.这就是我在思考算法的方式:

在此输入图像描述

但我仍然觉得用第二种方法我可以得到内存异常问题,因为在源和目标数据不匹配的某些步骤中,我将它们存储在缓冲区(数据表或列表等)中以进行下一个块比较.

任何人都可以指导我应该是什么样的好算法或更好的方法来解决这个问题?

注意:我不想使用LinkedServerSSIS.

Vla*_*nov 5

您的第二个解决方案似乎是尝试重新创建外部合并排序.如果您的数据不适合内存,这是一种有效的方法,但当您的数据集适合内存时,它是过度的.

每行2,400万行(8字节)只有~200MB的内存.两个数据集是400MB.现代桌面硬件上没有任何内容.

将两个数据集加载到内存中.在简单的数组中.在内存中排序数组.通过扫描两个已排序的数组来查找差异.你不需要花哨的LINQ.

这是伪代码.我们有Array1Array2.维护两个包含每个数组当前索引的变量:Idx1Idx2.沿阵列移动索引以查找LinkedColumn匹配的位置.

Idx1 = 0; Idx2 = 0;
while (true)
{
    // scan arrays until both indexes point to the same LinkedColumn
    // here we assume that both arrays are sorted by LinkedColumn
    // and that values in LinkedColumn are unique

    while (Idx1 < Array1.Length && Idx2 < Array2.Length &&
        Array1[Idx1].LinkedColumn < Array2[Idx2].LinkedColumn)
    {
        // move along Array1
        Idx1++;
    }

    while (Idx1 < Array1.Length && Idx2 < Array2.Length &&
        Array1[Idx1].LinkedColumn > Array2[Idx2].LinkedColumn)
    {
        // move along Array2
        Idx2++;
    }

    // at this point both indexes point to the same LinkedColumn
    // or one or both of the arrays are over

    if (Idx1 >= Array1.Length || Idx2 >= Array2.Length)
    {
        break;
    }

    // compare the values
    if (Array1[Idx1].CompareColumn != Array2[Idx2].CompareColumn)
    {
        // TODO: output/save/print the difference
    }

    Idx1++; Idx2++;
}
Run Code Online (Sandbox Code Playgroud)

要么

您可以将两个数据集转储到您选择的数据库中的两个表中,T1并在两个表中T2创建唯一索引LinkedColumn并运行此查询:

SELECT
     T1.LinkedColumn  AS SrcLinkedColumn
    ,T1.CompareColumn AS SrcCompareColumn
    ,T2.LinkedColumn  AS DstLinkedColumn
    ,T2.CompareColumn AS DstCompareColumn
FROM
    T1 INNER JOIN T2 ON T1.LinkedColumn = T2.LinkedColumn
WHERE
    T1.CompareColumn <> T2.CompareColumn
ORDER BY
    T1.LinkedColumn
;
Run Code Online (Sandbox Code Playgroud)

上面的伪代码执行与DBMS服务器为此查询执行的相同的合并连接.


小智 0

抱歉,我只能给你一个想法:

限制条件:

  • Target 拥有数百万条记录
  • 来源有数百万条记录
  • 内存有限

想法:

  1. 为此至少使用 2 台机器
  2. 一张为【源】,另一张为【目标】,有匹配的服务
  3. 通过调用服务将每n(块)记录从[Source]发送到[Target]机器,让它匹配记录,然后将结果发送回[Source]

奖金 :

  1. 使用1台以上的[目标]机器,并让[源]机器在异步和负载均衡的场景中充分利用它们

您可能会发现一些类似(或高级)的解决方案,例如:

  • [目标]和[源]可以利用共享内存(例如缓存服务器)来存储结果
  • 在它们之间使用真正的负载均衡器层,来处理对多台[目标]机器的多个请求
  • 使用队列/消息传递层
  • 甚至使用多个[源]和多个[目标]机器

抱歉,但(至少对我来说)这个箱子太大了,仅使用一台机器就无法处理

我希望至少这能给你一个想法