ฉันมีปัญหาด้านประสิทธิภาพการทำงานของ SQL ที่สำคัญเมื่อใช้การโทรแบบ async ฉันได้สร้างกรณีเล็ก ๆ เพื่อแสดงให้เห็นถึงปัญหา
ฉันได้สร้างฐานข้อมูลบน SQL Server 2016 ซึ่งอยู่ใน LAN ของเรา (ไม่ใช่ 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 (zip ของชุดข้อมูล JSON ที่ใหญ่กว่า))
ตอนนี้ถ้าฉันดำเนินการค้นหาใน 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 มิลลิวินาที
แต่เมื่อเปลี่ยนเป็นรหัส async:
string value = await command.ExecuteScalarAsync() as string;
ทันใดนั้นเวลาดำเนินการคือ1800 มิลลิวินาที ! นอกจากนี้ใน SQL Server Profiler ฉันเห็นว่าระยะเวลาการดำเนินการเคียวรีนานกว่าหนึ่งวินาที แม้ว่าคำค้นหาที่ดำเนินการซึ่งรายงานโดย profiler จะเหมือนกับเวอร์ชันที่ไม่ใช่ Async ทุกประการ
แต่มันแย่ลง ถ้าฉันเล่นกับ Packet Size ในสตริงการเชื่อมต่อฉันจะได้ผลลัพธ์ดังต่อไปนี้:
ขนาดแพ็คเก็ต 32768: [TIMING]: ExecuteScalarAsync ใน SqlValueStore -> เวลาที่ผ่านไป: 450 ms
ขนาดแพ็คเก็ต 4096: [TIMING]: ExecuteScalarAsync ใน SqlValueStore -> เวลาที่ผ่านไป: 3667 ms
ขนาดแพ็กเก็ต 512: [TIMING]: ExecuteScalarAsync ใน SqlValueStore -> เวลาที่ผ่านไป: 30776 ms
30,000 มิลลิวินาที !! ช้ากว่าเวอร์ชันที่ไม่ใช่ async มากกว่า 1,000 เท่า และ SQL Server Profiler รายงานว่าการเรียกใช้แบบสอบถามใช้เวลานานกว่า 10 วินาที ที่ไม่ได้อธิบายว่าอีก 20 วินาทีหายไปไหน!
จากนั้นฉันก็เปลี่ยนกลับไปใช้เวอร์ชันซิงค์และเล่นกับ Packet Size และแม้ว่าจะส่งผลกระทบต่อเวลาดำเนินการเพียงเล็กน้อย แต่ก็ไม่มีที่ไหนที่น่าทึ่งเท่ากับเวอร์ชัน async
ในฐานะที่เป็นด้านข้างหากใส่เพียงสตริงขนาดเล็ก (<100 ไบต์) ลงในค่าการดำเนินการสืบค้นแบบ async จะเร็วเท่ากับเวอร์ชันซิงค์ (ผลลัพธ์ใน 1 หรือ 2 มิลลิวินาที)
ฉันรู้สึกงุนงงกับเรื่องนี้มากโดยเฉพาะอย่างยิ่งเมื่อฉันใช้บิวท์อินSqlConnection
ไม่ใช่ ORM นอกจากนี้เมื่อค้นหาไปรอบ ๆ ฉันไม่พบสิ่งใดที่สามารถอธิบายพฤติกรรมนี้ได้ ความคิดใด ๆ ?