我在使用异步调用时遇到了严重的SQL性能问题.我创建了一个小 case 来证明这个问题.
我已经在驻留在LAN中的SQL Server 2016上创建了一个数据库(因此不是localDB).
在该数据库中,我有一个表WorkingCopy
,其中包含2列:
Id (nvarchar(255, PK))
Value (nvarchar(max))
DDL个
CREATE TABLE [dbo].[Workingcopy]
(
[Id] [nvarchar](255) NOT NULL,
[Value] [nvarchar](max) NULL,
CONSTRAINT [PK_Workingcopy]
PRIMARY KEY CLUSTERED ([Id] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
在该表中,我插入了一条记录(id
='PerfurnitTest',Value
是一个1.5mb的字符串(一个更大的JSON数据集的zip).
现在,如果我在SSMS中执行查询:
SELECT [Value]
FROM [Workingcopy]
WHERE id = 'perfunittest'
我立即得到了结果,我在SQL Servre Profiler中看到执行时间约为20毫秒.一切正常.
使用纯SqlConnection
从.NET(4.6)代码执行查询时:
// at this point, the connection is already open
var command = new SqlCommand($"SELECT Value FROM WorkingCopy WHERE Id = @Id", _connection);
command.Parameters.Add("@Id", SqlDbType.NVarChar, 255).Value = key;
string value = command.ExecuteScalar() as string;
执行时间也在20-30毫秒左右.
但将其更改为异步代码时:
string value = await command.ExecuteScalarAsync() as string;
执行时间突然变为1800 ms!同样在SQL Server Profiler中,我看到查询执行持续时间超过一秒.尽管探查器报告的已执行查询与非异步版本完全相同.
但情况变得更糟了.如果我在连接字符串中处理数据包大小,我会得到以下结果:
Packet size 32768 : [TIMING]: ExecuteScalarAsync in SqlValueStore -> elapsed time : 450 ms
Packet Size 4096 : [TIMING]: ExecuteScalarAsync in SqlValueStore -> elapsed time : 3667 ms
Packet size 512 : [TIMING]: ExecuteScalarAsync in SqlValueStore -> elapsed time : 30776 ms
30,000 ms!! 这比非异步版本慢30,000 ms0倍以上.SQL Server Profiler报告查询执行耗时超过10秒.这甚至不能解释剩下的20秒到哪里go 了!
然后我又切换回了同步版本,并对数据包的大小进行了调整,虽然它确实对执行时间产生了一些影响,但它没有异步版本那么引人注目.
另外,如果只将一个小字符串(<;100字节)放入值中,异步查询的执行速度与同步版本一样快(结果为1或2毫秒).
我真的很困惑,尤其是因为我使用的是内置的SqlConnection
,甚至不是ORM.此外,在四处搜索时,我发现没有任何东西可以解释这种行为.有什么 idea 吗?