1

我需要遍历 150 万行,对于行,我需要计算与所有其他行的差异。

目前我正在做类似的事情:

    // Mocked Data
    var myTable = new DataTable("hello");
    myTable.Columns.Add("ID", typeof (int));
    myTable.Columns.Add("Value", typeof(byte[]));
    var random = new Random();
    for (int i = 0; i < 1000; i++)
    {
        var row = myTable.NewRow();
        row["ID"] = i;
        var bitArray = new BitArray(50 * 50);
        for (int j = 0; j < 50*50; j++)
        {
            bitArray.Set(j, random.NextDouble() >= random.NextDouble());
        }

        byte[] byteArray = new byte[(int)Math.Ceiling((double)bitArray.Length / 8)];

        bitArray.CopyTo(byteArray, 0);

        row["Value"] = byteArray;
        myTable.Rows.Add(row);
    }
    // Mocked data complete.


    var calculated = new DataTable("calculated");
    calculated.Columns.Add("ID", typeof (int));
    calculated.Columns.Add("AaginstID", typeof (int));
    calculated.Columns.Add("ComputedIntersect", typeof(byte[]));
    calculated.Columns.Add("ComputedUnion", typeof(byte[]));
    for (int i = 0; i < myTable.Rows.Count; i++)
    {
        for (int j = i + 1; j < myTable.Rows.Count; j++)
        {
            var row = calculated.NewRow();
            row["ID"] = myTable.Rows[i]["ID"];
            row["AaginstID"] = myTable.Rows[j]["ID"];

            var intersectArray = new BitArray((byte[]) myTable.Rows[i]["Value"]);
            var unionArray = new BitArray((byte[])myTable.Rows[i]["Value"]);
            var jArray = new BitArray((byte[])myTable.Rows[j]["Value"]);


            intersectArray.And(jArray);
            unionArray.Or(jArray);

            var intersectByteArray = new byte[(int)Math.Ceiling((double)intersectArray.Length / 8)];
            var unionByteArray = new byte[(int)Math.Ceiling((double)unionArray.Length / 8)];

            intersectArray.CopyTo(intersectByteArray, 0);
            unionArray.CopyTo(unionByteArray, 0);

            row["ComputedIntersect"] = intersectByteArray;
            row["ComputedUnion"] = unionByteArray;
            calculated.Rows.Add(row);
        }
        // Real data is 1.5m+ rows, so need to do this incrementally
        // STORE DATA TO DB HERE
    }

我使用带有 TableLock 的 SQLBulkCopy 存储我的数据,我的 BatchSize 是默认值(0 - 整个批次)。将 150 万条记录保存到数据库有点慢(30/60 秒),所以我也愿意接受有关更改我的 SQL 存储机制的建议,但主要瓶颈是 C#。我的 BitArray 大小为 2500 位(我使用 50*50 因为它是一个网格,在代码中我允许可变网格大小,对于这个测试,假设它总是 2500 位)。

针对单行处理 150 万行大约需要 140 秒,这将花费太长时间来处理所有内容,因此我需要找到更好的方法。正在进行大量工作是为了对数据进行预处理,以便在需要时更快地检索,所以我可以将其搁置一天,但根据我的计算,这将需要近三年的时间来处理......

我在外循环的每个循环上将数据存储到数据库中,这样我就不会一次在内存中保存太多。数据设置不切实际,我确实使用 BitArray.Set 进行第一轮处理(生成 150 万行),这是一个瓶颈,但不需要修改。主要目标是让每一行的联合/交集与所有其他行相对,以便稍后我可以拉出相关的行,准备好去。因此,如果有更好的存储类型(数据库中的二进制(313)),或者有更好的方法来获得相同的结果,我愿意重写。

我考虑过编写一个 SQL CLR 函数,但我也不确定这是否是正确的方法。需要对数据进行预处理,因此我正在寻求有关最佳方法的帮助。

4

1 回答 1

0

我建议在数据库中进行所有计算。SQL Server 最擅长基于集合的操作,这使得它非常适合这些类型的问题。我简要介绍了您可以采取的步骤

  1. bcp 你所有的数据到一个临时表中。
  2. 使用您需要的计算值更新临时表。
  3. 插入到您的“真实”表中,从临时表中选择您想要的值。
于 2013-10-07T22:00:11.303 回答