我需要遍历 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 函数,但我也不确定这是否是正确的方法。需要对数据进行预处理,因此我正在寻求有关最佳方法的帮助。