为什么 SQLserver 上的并行 select 速度较慢?

Why are parallel select's on SQLserver slower?

我很困惑为什么 select 在 SqlServer 上并行 select 比 select 按顺序

慢很多

另外看起来增加并行度(线程)只会使延迟更大

这个小样本可以重现问题

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using SqlThreading;

var repository = new Repository();
Console.WriteLine("Prefetch");
await repository.GetData(0);

var identifiers = new List<int>();
for (int i=70; i<80; i++)
    identifiers.Add(i);

Console.WriteLine($"{Environment.NewLine}Sequential:");
foreach (var identifier in identifiers)
    await repository.GetData(identifier);

Console.WriteLine($"{Environment.NewLine}Parallel:");
Parallel.ForEach(identifiers, new ParallelOptions {MaxDegreeOfParallelism = identifiers.Count}, async i => 
    await repository.GetData(i));

我的存储库就是这样(使用 Dapper):

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Threading.Tasks;
using Dapper;

namespace SqlThreading
{
    public class Repository
    {
        private readonly string _connectionString;

        public Repository()
        {
            _connectionString = new SqlConnectionStringBuilder
            {
                DataSource = "SqlServer",
                InitialCatalog = "Database",
                IntegratedSecurity = true,
                MinPoolSize = 10,
            }.ToString();
        }

        public async Task<IEnumerable<dynamic>> GetData(int id)
        {
            await using var conn = new SqlConnection(_connectionString);
            var sw = Stopwatch.StartNew();
            var result = await conn.QueryAsync($"select top 1 * from dbo.MyTable id = @id", new {id});
            sw.Stop();
            Console.WriteLine($"Query took {sw.ElapsedMilliseconds} ms");
            return result;
        }
    }
}

根据我的设置,它将产生如下内容:

Prefetch
Query took 2877 ms

Sequential:
Query took 46 ms
Query took 24 ms
Query took 23 ms
Query took 26 ms
Query took 28 ms
Query took 23 ms
Query took 24 ms
Query took 26 ms
Query took 33 ms
Query took 30 ms

Parallel:
Query took 55 ms
Query took 153 ms
Query took 154 ms
Query took 154 ms
Query took 154 ms
Query took 155 ms
Query took 155 ms
Query took 67 ms
Query took 158 ms

正如@JeroenMostert 所指出的,问题可能出在 System.Data.SqlClient 并行性尚未完全成熟的地方

在此之前,我们将使用 Microsoft.Data.SqlClient,它具有更好的并行性支持

在并行选项中,它可能会打开更多到 SQL 服务器的连接。打开连接是一项相对繁重的操作,因此它们会自动透明地为您汇集。在您的第一组查询中,.NET 将重新使用相同的连接。在并行选项中,它需要进行几个额外的连接。

使用扩展事件会话查看连接 ID 进行确认。或者再次 运行 并行循环,您可能会发现它花费的时间与串行示例大致相同。

最好能准确了解您要测试的内容。您是要查看并行操作对客户端或服务器的影响吗?

如果是服务器,那么您需要对其施加适当的负载,并可能进行更复杂的查询。或者你真正想在服务器上做的任何事情的代表性负载。有很好的免费负载测试工具可以比您自己编写的小型测试工具更有效地做到这一点。

如果是客户,那么您需要再次确定您想要实现的目标。 运行 大量并行的小查询...为什么?如果他们在服务器上实际上占用了 0 时间,那么 运行ning 并行就没有意义了。如果他们发回大量数据,那么也许值得进一步研究。如果他们花了很长时间但没有返回太多数据,那就太好了,可能是 运行ning 并行的情况。无论哪种方式,您都应该相应地构建测试和查询。