비동기 호출을 사용할 때 주요 SQL 성능 문제가 있습니다. 문제를 설명하기 위해 작은 케이스를 만들었습니다.
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
= 'PerfUnitTest' Value
는 1.5MB 문자열 (더 큰 JSON 데이터 세트의 zip)).
이제 SSMS에서 쿼리를 실행하면 다음과 같습니다.
SELECT [Value]
FROM [Workingcopy]
WHERE id = 'perfunittest'
즉시 결과를 얻었고 SQL Servre Profiler에서 실행 시간이 약 20 밀리 초라는 것을 알 수 있습니다. 모두 정상입니다.
일반을 사용하여 .NET (4.6) 코드에서 쿼리를 실행할 때 SqlConnection
:
// 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;
실행 시간이 갑자기 1800ms ! 또한 SQL Server Profiler에서 쿼리 실행 기간이 1 초 이상임을 알 수 있습니다. 프로파일 러에서보고 한 실행 된 쿼리는 비동기 버전과 완전히 동일합니다.
그러나 더 나빠집니다. 연결 문자열에서 패킷 크기를 가지고 놀면 다음과 같은 결과가 나타납니다.
패킷 크기 32768 : [TIMING] : SqlValueStore에서 ExecuteScalarAsync-> 경과 시간 : 450ms
Packet Size 4096 : [TIMING] : SqlValueStore의 ExecuteScalarAsync-> 경과 시간 : 3667 ms
패킷 크기 512 : [TIMING] : SqlValueStore의 ExecuteScalarAsync-> 경과 시간 : 30776 ms
30,000ms !! 비동기 버전보다 1000 배 이상 느립니다. 그리고 SQL Server Profiler는 쿼리 실행에 10 초 이상 걸린다고보고합니다. 그것은 다른 20 초가 어디로 갔는지도 설명하지 않습니다!
그런 다음 동기화 버전으로 다시 전환하고 패킷 크기를 사용해 보았습니다. 실행 시간에 약간의 영향을 미쳤지 만 비동기 버전만큼 극적인 것은 아닙니다.
참고로 값에 작은 문자열 (100 바이트 미만) 만 입력하면 비동기 쿼리 실행이 동기화 버전만큼 빠릅니다 (결과는 1ms 또는 2ms).
특히 SqlConnection
ORM이 아닌 내장을 사용하고 있기 때문에 정말 당황합니다 . 또한 주변을 검색 할 때이 동작을 설명 할 수있는 것을 찾지 못했습니다. 어떤 아이디어?