C# 使用LINQPad将数据插入到sqlce数据库中,linqtosql会随着时间的推移变得越来越慢,对此我能做些什么?

C# 使用LINQPad将数据插入到sqlce数据库中,linqtosql会随着时间的推移变得越来越慢,对此我能做些什么?,c#,sql-server-ce,linqpad,C#,Sql Server Ce,Linqpad,我在磁盘上有一个SQL CE 4.0数据库,还有一个我想用来填充该数据库的程序 我正在使用内置(到LINQPad)linq2sql系统。我注意到,随着时间的推移,插入一批行所需的时间越来越长,最终看起来程序已经慢到爬行 是否有某种缓存或类似的东西使它变慢了?如果有的话,我能做些什么来避免这种减速 这是我用来测试的简单测试表: CREATE TABLE dummy ( id int not null primary key identity (1, 1), value nvarch

我在磁盘上有一个SQL CE 4.0数据库,还有一个我想用来填充该数据库的程序

我正在使用内置(到LINQPad)linq2sql系统。我注意到,随着时间的推移,插入一批行所需的时间越来越长,最终看起来程序已经慢到爬行

是否有某种缓存或类似的东西使它变慢了?如果有的话,我能做些什么来避免这种减速

这是我用来测试的简单测试表:

CREATE TABLE dummy
(
    id int not null primary key identity (1, 1),
    value nvarchar(20) not null
)
我的测试程序是:

void Main()
{
    for (int iteration = 1; iteration <= 1000; iteration++)
    {
        Stopwatch sw = Stopwatch.StartNew();
        for (int row = 0; row < 100; row++)
            dummy.InsertOnSubmit(new dummy { value = "row#" + row });
        var create = sw.ElapsedMilliseconds;
        SubmitChanges();
        sw.Stop();
        var total = sw.ElapsedMilliseconds;
        Debug.WriteLine("iteration " + iteration + ", create=" + create + ", total=" + total);
    }
}
如您所见,调用
SubmitChanges
所需的时间越来越长,但每次迭代我都会插入相同数量的实体

请注意,我完全知道我不会获得像批量插入之类的速度,但如果可能的话,我仍然希望避免这种减速

还要注意的是,如果我现在重新运行程序,数据库中已经有很多行,那么时间会再次开始变短:

iteration 1, create=1, total=51
iteration 2, create=0, total=50
iteration 3, create=0, total=45
iteration 4, create=0, total=45
所以,在我看来,有一些东西在记忆中不断成长


除了周期性地停止程序并重新启动它(这对于我真正正在做的事情是可以做到的,但我想避免它)之外,还有什么我可以关闭、重置、转储或其他方法来修复此问题。

听起来您想从LINQPad内将数据批量复制到SQL Server。下面是我用来做这件事的方法:

void BCP<TRow> (IEnumerable<TRow> rows)
{
    if (rows.Count() == 0) return;
    var dt = new DataTable ();
    var metaTable = _db.Mapping.GetTable (typeof (TRow));
    var columns = metaTable.RowType.DataMembers.Where (dm => dm.Association == null);
    var transformers = new List<Func<TRow, object>>();
    foreach (var columnX in columns)
    {
        var column = columnX;
        dt.Columns.Add (column.Name, L2sToDataTable (column.Type));
        transformers.Add (row => L2sToDataTable (row.GetType().GetField (column.Name).GetValue (row)));
    }
    foreach (var row in rows)
        dt.Rows.Add (transformers.Select (t => t (row)).ToArray());

    _db.Connection.Open();
    Console.Write ("Bulk copying " + metaTable.TableName + "... ");
    var bcp = new SqlBulkCopy ((SqlConnection)_db.Connection) { DestinationTableName = metaTable.TableName, BulkCopyTimeout = 300 };
    bcp.BatchSize = 20;
    bcp.NotifyAfter = 20;
    bcp.SqlRowsCopied += (sender, args) => Console.Write (args.RowsCopied + " rows... ");
    bcp.WriteToServer (dt);
    _db.Connection.Close();
    Console.WriteLine ("Done");
}

Type L2sToDataTable (Type l2sType)
{
    if (l2sType == typeof (Binary)) return typeof (byte[]);
    if (l2sType.IsGenericType && l2sType.GetGenericTypeDefinition() == typeof (Nullable<>)) return l2sType.GetGenericArguments()[0];
    return l2sType;
}

object L2sToDataTable (object l2sValue)
{
    if (l2sValue == null) return DBNull.Value;
    if (l2sValue is Binary) return ((Binary) l2sValue).ToArray();
    return l2sValue;
}
void BCP(IEnumerable行)
{
if(rows.Count()==0)返回;
var dt=新数据表();
var元表=_db.Mapping.GetTable(typeof(TRow));
var columns=metaTable.RowType.DataMembers.Where(dm=>dm.Association==null);
var变压器=新列表();
foreach(列中的变量columnX)
{
var column=columnX;
dt.Columns.Add(column.Name,l2stodata(column.Type));
Add(row=>L2STODATABLE(row.GetType().GetField(column.Name).GetValue(row));
}
foreach(行中的变量行)
dt.Rows.Add(transformers.Select(t=>t(row)).ToArray();
_db.Connection.Open();
Console.Write(“批量复制”+metaTable.TableName+”);
var bcp=newsqlbulkcopy((SqlConnection)_db.Connection){DestinationTableName=metaTable.TableName,BulkCopyTimeout=300};
bcp.BatchSize=20;
bcp.after=20;
bcp.SqlRowsCopied+=(发送方,args)=>Console.Write(args.RowsCopied+“行…”);
bcp.WriteToServer(dt);
_db.Connection.Close();
Console.WriteLine(“完成”);
}
L2STODATABLE类型(l2sType类型)
{
if(l2sType==typeof(Binary))返回typeof(byte[]);
if(l2sType.IsGenericType&&l2sType.GetGenericTypeDefinition()==typeof(可空))返回l2sType.GetGenericArguments()[0];
返回l2sType;
}
对象L2STODATABLE(对象l2sValue)
{
if(l2sValue==null)返回DBNull.Value;
如果(l2sValue是二进制的),则返回((二进制的)l2sValue).ToArray();
返回L2S值;
}

这避免了对象关系映射器(如LINQ到SQL)的缓存内存开销,同时利用后者的元数据。

将其移动到适当的(控制台)应用程序,并每隔N条记录重新创建DataContext。Henk说,首先创建虚拟对象列表,然后使用InsertAllOnSubmit。要获得最大性能,请创建一个适当的应用程序,并使用SqlCeBulkCopy而不是LINQ To SQLServer Compact Edition不允许使用SqlBulkCopy,是吗?L2STODATABLE的impl是什么?抱歉,James。我把它加进去了。没有比不完整的样品更糟糕的了!
var column=columnX的好处是什么赋值与在后续语句中直接引用'columnX'foreach变量?foreach循环中的临时列变量在预C#5天内是必需的,这样您就可以在lambda表达式中关闭变量,而不会在循环迭代之间更改。现在不再需要了。
void BCP<TRow> (IEnumerable<TRow> rows)
{
    if (rows.Count() == 0) return;
    var dt = new DataTable ();
    var metaTable = _db.Mapping.GetTable (typeof (TRow));
    var columns = metaTable.RowType.DataMembers.Where (dm => dm.Association == null);
    var transformers = new List<Func<TRow, object>>();
    foreach (var columnX in columns)
    {
        var column = columnX;
        dt.Columns.Add (column.Name, L2sToDataTable (column.Type));
        transformers.Add (row => L2sToDataTable (row.GetType().GetField (column.Name).GetValue (row)));
    }
    foreach (var row in rows)
        dt.Rows.Add (transformers.Select (t => t (row)).ToArray());

    _db.Connection.Open();
    Console.Write ("Bulk copying " + metaTable.TableName + "... ");
    var bcp = new SqlBulkCopy ((SqlConnection)_db.Connection) { DestinationTableName = metaTable.TableName, BulkCopyTimeout = 300 };
    bcp.BatchSize = 20;
    bcp.NotifyAfter = 20;
    bcp.SqlRowsCopied += (sender, args) => Console.Write (args.RowsCopied + " rows... ");
    bcp.WriteToServer (dt);
    _db.Connection.Close();
    Console.WriteLine ("Done");
}

Type L2sToDataTable (Type l2sType)
{
    if (l2sType == typeof (Binary)) return typeof (byte[]);
    if (l2sType.IsGenericType && l2sType.GetGenericTypeDefinition() == typeof (Nullable<>)) return l2sType.GetGenericArguments()[0];
    return l2sType;
}

object L2sToDataTable (object l2sValue)
{
    if (l2sValue == null) return DBNull.Value;
    if (l2sValue is Binary) return ((Binary) l2sValue).ToArray();
    return l2sValue;
}