-1

我正在考虑将 Sql Server Compact 4.0 用于 Windows 服务应用程序(不是 Web)的数据存储。

我担心多个调用者的服务性能,所以我起草了一个小测试,结果与我的预期完全相反。(见下面的代码)

该测试只是将 500 行添加到一个简单数据库中的表中,该数据库是使用 Entity Framework 5.0 首先使用代码创建的。

它添加行的方式很特别。它调用 AddRow 方法 500 次,并将其留给 AddRow 方法来创建 DbContext 的实例,然后添加行然后处置上下文。我这样做的原因是调用 AddRow 500 次的循环是为了模拟来自客户端的 500 次调用(尽管您可能会说这是不现实的快速连续调用)

为了模拟多个客户端,我启动了一些任务来完成 LoadData 方法的工作。

现在进行观察:一个线程调用 LoadData,最后调用 AddRow 500 次,我的工作站上添加 500 行的时间约为 50 秒(每秒只有 10 行!)

有 5 个线程调用 LoadData,我希望每个线程最多在 50 秒内执行,但 5 个线程中有 4 个在 3 秒内完成,最后一个线程在 10 秒内完成。

我假设最后一个线程运行的时间更长,因为 3 秒后其他 4 个线程都完成了,所以最后一个线程单独运行,在这个测试中单独运行似乎会导致灾难性的性能。

我应该注意,如果我从 Sql Compact 更改为 Local DB,那么性能完全符合预期:每个线程运行的时间大致相同,大约 3 秒。

这是完整的代码和 app.config,您应该可以将其剪切并粘贴到新的 Visual Studio 2012 控制台项目中。

目前,我最好的猜测是,在单线程测试中,没有发生连接池,但在其他测试中不知何故存在?这对我来说没有任何意义,我的问题是应该怎么做,以使单个调用者线程的测试运行与多个调用者线程一样快?

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;

namespace SqlCompactPerf
{
    class Program
    {
        private const int MaxThreads = 5;
        private const int RowsToInsert = 500;
        private static void Main()
        {
            using (var context = new MyContext())
                context.Database.Delete();


            var tasks = new List<Task>();
            for (var threadCount = 1; threadCount <= MaxThreads; threadCount++)
                tasks.Add(Task<TimeSpan>.Factory.StartNew(LoadData)
                                        .ContinueWith(x => 
                                           Console.WriteLine("Time: {0}", x.Result)));

            Task.WaitAll(tasks.ToArray());

            using (var context = new MyContext())
                Console.WriteLine("Expecting {0}, Found {1}",
                    RowsToInsert * MaxThreads,
                    context.Rows.Count());

        }

        static TimeSpan LoadData()
        {
            var watch = new Stopwatch();
            watch.Start();
            for (var i = 1; i <= RowsToInsert; i++)
            {
                AddRow(DateTime.Now.ToString(CultureInfo.InvariantCulture));
            }
            watch.Stop();

            return watch.Elapsed;
        }

        static void AddRow(string data)
        {
            using (var context = new MyContext())
            {
                context.Rows.Add(new Row { Id = Guid.NewGuid(), Data = data });
                context.SaveChanges();
            }
        }
    }
    class MyContext : DbContext
    {
        public DbSet<Row> Rows { get; set; }
    }

    internal class Row
    {
        public Guid Id { get; set; }
        public String Data { get; set; }
    }
}

这是 App.Config 文件:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="System.Data.SqlServerCe.4.0" />
      </parameters>
    </defaultConnectionFactory>
  </entityFramework>
  <!--<entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>
  </entityFramework>-->
</configuration>
4

1 回答 1

1

建议在应用程序的整个生命周期内始终保持至少一个数据库连接打开,因为打开第一个连接是资源密集型的。但不要跨线程共享同一个 SqlCeConnection 对象。此链接解释了一种您可以采用的方法:http: //matthewmanela.com/blog/sql-ce-3-5-with-linq-to-sql/ - 此外,使用 EF5 或更早版本添加许多行很慢,因为一个错误,我已在 EF6 中修复 - 请在此处查看我的博客文章以获取更多信息:http ://erikej.blogspot.dk/2013/06/inserting-many-rows-with-entity.html

于 2013-08-16T06:42:56.780 回答