Zaman uyumsuz çağrıları kullanırken önemli SQL performans sorunları yaşıyorum. Sorunu göstermek için küçük bir vaka oluşturdum.
LAN'ımızda bulunan (yani bir localDB değil) SQL Server 2016'da bir veritabanı oluşturdum.
Bu veritabanında WorkingCopy
2 sütunlu bir tablom var:
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]
Bu tabloya tek bir kayıt id
ekledim ( = 'PerfUnitTest', Value
1.5mb'lik bir dizedir (daha büyük bir JSON veri kümesinin zip'i)).
Şimdi, sorguyu SSMS'de yürütürsem:
SELECT [Value]
FROM [Workingcopy]
WHERE id = 'perfunittest'
Hemen sonucu alıyorum ve SQL Servre Profiler'da yürütme süresinin yaklaşık 20 milisaniye olduğunu görüyorum. Herşey normal.
Sorguyu .NET (4.6) kodundan bir düz kullanarak çalıştırırken 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;
Bunun uygulama süresi de yaklaşık 20-30 milisaniyedir.
Ancak onu eşzamansız koda değiştirirken:
string value = await command.ExecuteScalarAsync() as string;
Uygulama süresi aniden 1800 ms oldu ! Ayrıca SQL Server Profiler'da sorgu yürütme süresinin bir saniyeden fazla olduğunu görüyorum. Profil oluşturucu tarafından bildirilen yürütülen sorgu, Async olmayan sürümle tamamen aynı olsa da.
Ama daha da kötüleşiyor. Bağlantı dizesinde Paket Boyutu ile oynarsam, aşağıdaki sonuçları alıyorum:
Paket boyutu 32768: [TIMING]: SqlValueStore'da ExecuteScalarAsync -> geçen süre: 450 ms
Paket Boyutu 4096: [TIMING]: SqlValueStore'da ExecuteScalarAsync -> geçen süre: 3667 ms
Paket boyutu 512: [TIMING]: SqlValueStore'da ExecuteScalarAsync -> geçen süre: 30776 ms
30.000 ms !! Bu, eşzamansız olmayan sürümden 1000 kat daha yavaştır. Ve SQL Server Profiler, sorgu yürütmenin 10 saniyeden fazla sürdüğünü bildiriyor. Bu, diğer 20 saniyenin nereye gittiğini bile açıklamıyor!
Sonra senkron versiyona geri döndüm ve ayrıca Packet Size ile oynadım ve yürütme süresini biraz etkilemesine rağmen, hiçbir yerde asenkron versiyondaki kadar dramatik değildi.
Bir yan not olarak, değere yalnızca küçük bir dize (<100 bayt) koyarsa, eşzamansız sorgu yürütme, eşitleme sürümü kadar hızlıdır (sonuç 1 veya 2 ms'dir).
Bu beni gerçekten şaşkına çeviriyor, özellikle SqlConnection
bir ORM bile değil , yerleşik olanı kullandığım için. Ayrıca etrafta arama yaparken, bu davranışı açıklayabilecek hiçbir şey bulamadım. Herhangi bir fikir?