并行执行不同的DbContexts比非并行版本

时间:2015-12-01 07:57:13

标签: c# entity-framework sql-server-2012 task-parallel-library

我有一个包含2列的简单表(一个是identity,另一个是char列:

CREATE TABLE [dbo].[tbl]
(
    [id] [INT] IDENTITY(1,1) NOT NULL,
    [col] [CHAR](32) NULL,
    CONSTRAINT [PK_tbl] PRIMARY KEY CLUSTERED ([id] ASC)
)

我们有一个执行长时间运行的功能。这是一些伪代码:

void doWork()
{
    using(context)
    {
        doLongPart1(context);
        ...
        doLongPartN(context);
    }
}

现在我试图使用每个自己的上下文来分离那些处于不同任务中的那些。但令人惊讶的是,带有任务的版本需要更多时间而没有任务我在这里插入10,000行。时间为:~54000ms表示没有任务的版本,~57000ms表示任务。我正在使用EF6.0,这里是重现的完整代码:

初始版

static void Main(string[] args)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    var c = 10000;

    var c1 = new TestEntities();
    for (int i = 1; i < c / 2; i++)
        c1.tbls.Add(new tbl { col = i.ToString() });

    c1.SaveChanges();

    var c2 = new TestEntities();
    for (int i = c / 2; i < c; i++)
        c2.tbls.Add(new tbl { col = i.ToString() });

    c2.SaveChanges();

    stopwatch.Stop();

    Console.WriteLine(stopwatch.ElapsedMilliseconds);
    Console.ReadLine();
}

包含任务的版本

static void Main(string[] args)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    var c = 10000;
    Task[] tasks = new Task[2];

    tasks[0] = Task.Run(() =>
    {
        var c1 = new TestEntities();

        for (int i = 1; i < c / 2; i++)
            c1.tbls.Add(new tbl { col = i.ToString() });
        c1.SaveChanges();
    });

    tasks[1] = Task.Run(() =>
    {
        var c2 = new TestEntities();

        for (int i = c / 2; i < c; i++)
            c2.tbls.Add(new tbl { col = i.ToString() });
        c2.SaveChanges();
    });

    Task.WaitAll(tasks);

    stopwatch.Stop();
    Console.WriteLine(stopwatch.ElapsedMilliseconds);

    Console.ReadLine();
}   

我还尝试通过存储过程执行此操作:

CREATE PROC spTbl @s CHAR(32)
AS
    INSERT INTO dbo.tbl (col)
    VALUES (@s)

和代码:

static void Main(string[] args)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    var c = 10000; 
    Task[] tasks = new Task[2];

    tasks[0] = Task.Run(() =>
    {
        var c1 = new TestEntities();

        for (int i = 1; i < c / 2; i++)
            c1.spTbl(i.ToString());
    });

    tasks[1] = Task.Run(() =>
    {
        var c2 = new TestEntities();

        for (int i = c / 2; i < c; i++)
            c2.spTbl(i.ToString());
    });

    Task.WaitAll(tasks);
}

我甚至尝试配置SQL Server:

sp_configure 'show advanced options', 1;
GO
RECONFIGURE WITH OVERRIDE;
GO
sp_configure 'max degree of parallelism', 8;
GO
RECONFIGURE WITH OVERRIDE;
GO

但对我来说没有任何作用。有人能指出我正确的方向吗?

1 个答案:

答案 0 :(得分:1)

c#程序不会使您的数据库更快。

如果问题在于数据库中插入操作的速度,那么使其并行不会解除瓶颈,它仍然是数据库中的插入操作。

你通常可以看到的是两(3)件事

1)数据库服务器中的驱动器/ SSD(或更多内存)速度更快

2)减少索引数量,因为这些索引都必须在插入操作上更新

对于某些操作,您甚至可以删除索引,插入所需的所有数据,然后重新创建索引,因为索引只会在每次插入行时更新一次

更新:现在我更详细地查看您的数字,在我看过的应用程序中,1000次查询/秒并不少见。

更新2:您可能会看到的一个可能的解决方案是批量插入https://efbulkinsert.codeplex.com/,因为即使使用您的存储过程,您的开销也是查询数量而不是查询(假设您没有索引和计算列)