c# - 列表的性能问题

标签 c# performance list for-loop

我的数据库中有 10 亿条记录,我需要用 20 个值随机更新所有行。
所以,对于每随机 5000 万条记录,需要更新 1 个值。
所以,我想到生成一个包含 10 亿个数字的列表,然后从该列表中随机选择 5000 万条记录,然后从该列表中删除这 5000 万条记录,等等。

我的代码:

列表创建:

List<long> LstMainList = new List<long>();
for (int i = 1; i <= 999999999; i++)
{
   LstMainList.Add(i);
}

新空列表: List<TableData> Table1 = new List<TableData>();

选择随机数并将它们添加到新列表并从包含 10 亿个项目的主列表中删除项目。

Random rand = new Random();

for (int a = 0; a < 50000000; a++)
{
     int lstindex = rand.Next(LstMainList.Count);

     Int64 lstData = LstMainList[lstindex];

     Table1.Add(new TableData { MESSAGE_ID = lstData });

     LstMainList.RemoveAt(lstindex);

     if (a % 100000 == 0)
     {
         if (previousThread != null)
         {
              previousThread.Join();
         }

          List<TableData> copyList = Table1.ToList();

          previousThread = new Thread(() => BulkCopyList(copyList, "PLAN_TABLE_1"));
          previousThread.Start();

          Table1.Clear();
       }
}

现在,我的问题是:在 LstMainList.RemoveAt(lstindex); 行,从 MainList 中删除索引需要很长时间,因为它包含 10 亿条记录。

有没有一种简单的方法可以从列表中删除记录?或任何其他方式使这变得简单?

最佳答案

首先 - 使用 array 作为 id 而不是 list(特别是没有初始化容量)

int idsCount = 100000000;
long[] ids = new long[idsCount];

for(long i = 1; i < idsCount; i++)
    ids[i] = i;

使用Fisher–Yates随机播放数组中的 ID

Random rnd = new Random();
int n = idsCount;
while(n > 1)
{
    int k = rnd.Next(n);
    n--;
    long temp = ids[n];
    ids[n] = ids[k];
    ids[k] = temp;
}

使用随机排列的 ID,您无需修改​​ ID 列表。在随机位置移除项目是非常昂贵的操作。如果您删除位置 0 的项目,则应将整个列表复制到新数组。现在您可以迭代 ids 数组。

或者您可以使用 morelinq Batch创建批处理的 TableData 并批量处理它们:

int size = 100000;
foreach(var batch in ids.Batch(size, id => new TableData { MESSAGE_ID = id }))
{
   var copyList = batch.ToList();
   // ...
}

更新:因此您需要不同大小的批处理,您可以使用以下扩展方法从数组中获取项目范围:

public static IEnumerable<T> GetRange<T>(
     this T[] array, int startIndex, int count)
{
    for (int i = startIndex; i < startIndex + count; i++)
        yield return array[i];
}

因此,从索引 20000 开始获取 5000 个 TableData 将如下所示:

var copyList = ids.GetRange(20000, 5000)
                  .Select(id => new TableData { MESSAGE_ID = id })
                  .ToList();

当然,更有效的方法是迭代 ids 数组,并将项目添加到具有预初始化容量的列表中:

int size = 5000;
int startIndex = 20000;
List<TableData> copyList = new List<TableData>(size);
for (int i = startIndex; i < startIndex + size; i++)
    copyList.Add(new TableData { MESSAGE_ID = ids[i] });

更进一步,我会将 TableData 对象的创建移动到执行批量复制的线程。并且刚刚传递了它应该使用的 ID 序列。

关于c# - 列表的性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25198419/

相关文章:

c# - 在打开的cmd中运行命令

c# - WPF 中 DataGrid 的双向绑定(bind)

c# - .NET的DateTime.ToString(“s”)的Delphi等效项(可排序的DateTime)

python - Python数据列表问题

c# - 将列表(ObservableCollection)复制到另一个

python-3.x - 为什么 Python 列表推导最后会打印一个 "None"的列表?

c# - 探索/调查/理解类层次结构和新项目工作原理的最佳方式

performance - HTTP 请求与文件大小?

sql - 我怎样才能使这个查询更有效地检测多个帐户并与 has_many 一起玩?

performance - localhost Redis Db 的往返成本是多少?可以忽略吗?