ConnectionPooling或缺乏ConnectionPooling,可以解释这个奇怪的Sql Compact性能

时间:2013-08-15 11:17:43

标签: .net performance entity-framework sql-server-ce

我正在考虑将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秒内执行,而是在3秒内完成5个线程中的4个,在10秒内完成最后一个线程。

我假设最后一个线程运行的时间更长,因为3秒后其他4个线程已经完成,所以最后一个线程单独运行,看起来在此测试中运行solo会导致灾难性的性能。

我应该注意,如果我从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>

1 个答案:

答案 0 :(得分:1)

建议始终在应用的生命周期内保持至少一个数据库连接处于打开状态,因为打开第一个连接是资源密集型的。但是不要跨线程共享相同的SqlCeConnection对象。此链接解释了您可以调整的方法:http://matthewmanela.com/blog/sql-ce-3-5-with-linq-to-sql/ - 此外,使用EF5或更早版本添加许多行的速度很慢,因为我在EF6中修复了一个错误 - 请参阅我的博客文章以获取更多信息:{{ 3}}