C# 使用DataTable.Add时的极端性能差异

C# 使用DataTable.Add时的极端性能差异,c#,.net,performance,C#,.net,Performance,请看下面的程序。这是不言自明的,但我还是要解释:) 我有两种方法,一种快一种慢。这些方法的作用完全相同:它们创建一个包含50000行和1000列的表。我向表中可变数量的列写入数据。在下面的代码中,我选择了10个(NUM\u COLS\u TO\u WRITE\u TO) 换句话说,1000列中只有10列实际包含数据。好啊这两种方法之间的唯一区别是,快速方法填充列,然后调用DataTable.AddRow,而慢速方法在后面调用。就这样 然而,性能上的差异令人震惊(无论如何对我来说)。快速版本几乎完

请看下面的程序。这是不言自明的,但我还是要解释:)

我有两种方法,一种快一种慢。这些方法的作用完全相同:它们创建一个包含50000行和1000列的表。我向表中可变数量的列写入数据。在下面的代码中,我选择了10个(
NUM\u COLS\u TO\u WRITE\u TO

换句话说,1000列中只有10列实际包含数据。好啊这两种方法之间的唯一区别是,快速方法填充列,然后调用
DataTable.AddRow
,而慢速方法在后面调用。就这样

然而,性能上的差异令人震惊(无论如何对我来说)。快速版本几乎完全不受我们写入的列数的影响,而慢速版本则呈线性上升。例如,当我写入的列数为20时,快速版本需要2.8秒,而慢速版本需要一分钟以上

这到底是怎么回事

我认为添加
dt.BeginLoadData
可能会有所不同,在某种程度上确实如此,它将时间从61秒减少到了~50秒,但这仍然是一个巨大的差异

当然,显而易见的答案是,“好吧,不要那样做。”好的。当然但究竟是什么导致了这一现象?这是预期的行为吗?我当然没想到。:)

公共类程序
{
私有const int NUM_ROWS=50000;
private const int NUM_COLS_TO_WRITE_TO=10;
私有const int NUM_COLS_TO_CREATE=1000;
私有静态void AddRowFast(){
DataTable dt=新的DataTable();
//添加一个包含1000列的表
for(int i=0;i
更新


在慢速版本中调用
theRow.BeginEdit
theRow.EndEdit
会使慢速版本或多或少保持不变(在我的机器上约4秒)。如果我确实对表有一些限制,我想这对我来说可能是有意义的。

当附加到表时,要记录和跟踪每次更改的状态,需要做更多的工作

例如,如果你这样做

theRow.BeginEdit();

for (int j = 0; j < NUM_COLS_TO_WRITE_TO; j++)
{
   theRow[j] = "whatever";
}

theRow.CancelEdit();
theRow.BeginEdit();
for(int j=0;j
然后在
BeginEdit()
中,它将复制行的内容,以便在任何时候,您都可以回滚,而上述操作的最终结果是再次生成一个空行,而不包含
任何内容。即使在
BeginLoadData
模式下,这仍然是可能的。按照
BeginEdit
的路径,如果连接到一个数据表,最终您会进入一个显示它只是复制每个列的每个值来存储原始状态,以防需要取消-这里没有太大的魔力。另一方面,如果不附加到数据表,则在
BeginEdit
中不会发生太多事情,并且会很快退出

EndEdit()
同样非常重(当附加时),因为这里检查了所有约束等(最大长度、列是否允许空值等)。此外,它还触发一系列事件,明确地释放了在取消编辑时使用的存储空间,并可通过
DataTable.GetChanges()
调用,这在
BeginLoadData
中仍然是可能的。实际上,查看源代码时,所有
BeginLoadData
似乎要做的就是关闭约束检查和索引


因此,这描述了
BeginEdit
EditEdit
的功能,它们在附加或不附加存储内容时是完全不同的。现在考虑一个单一的<代码> Too[j]=“无论如何”<代码>,它可以在索引器设置器上看到,它调用“代码> NeXEdgEng/<代码>,然后在每一个调用上调用<代码>编辑Ed>代码(如果它不是已经在编辑中,因为您明确地调用了<代码>初学者> 较早)。这意味着每次调用时,它都会复制并存储行中每列的每个值。所以你做了10次,这意味着你的1000列数据表,超过50000行,这意味着它分配了500000000个对象。除此之外,在每次更改后都会触发所有其他版本控制、检查和事件,因此,总的来说,将行附加到DataTable时要比不附加时慢得多。

我认为解释非常简单。什么时候
theRow.BeginEdit();

for (int j = 0; j < NUM_COLS_TO_WRITE_TO; j++)
{
   theRow[j] = "whatever";
}

theRow.CancelEdit();