Trong một kịch bản nhiều luồng, tôi gặp vấn đề với truy vấn EF cụ thể. Nó thường rẻ và nhanh chóng:Sự chậm trễ nghiêm trọng của EF và SQL
Context.MyEntity
.Any(se => se.SameEntity.Field == someValue
&& se.AnotherEntity.Field == anotherValue
&& se.SimpleField == simpleValue
// few more simple predicates with fields on the main entity
);
này biên dịch thành một truy vấn SQL rất hợp lý:
SELECT
CASE WHEN (EXISTS (SELECT
1 AS [C1]
FROM (SELECT [Extent1].[Field1] AS [Field1]
FROM [dbo].[MyEntity] AS [Extent1]
INNER JOIN [dbo].[SameEntity] AS [Extent2] ON [Extent1].[SameEntity_Id] = [Extent2].[Id]
WHERE (N'123' = [Extent2].[SimpleField]) AND (123 = [Extent1].[AnotherEntity_Id]) AND -- further simple predicates here --) AS [Filter1]
INNER JOIN [dbo].[AnotherEntity] AS [Extent3] ON [Filter1].[AnotherEntity_Id1] = [Extent3].[Id]
WHERE N'123' = [Extent3].[SimpleField]
)) THEN cast(1 as bit) ELSE cast(0 as bit) END AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable1]
Truy vấn, nói chung, có kế hoạch truy vấn tối ưu, sử dụng các chỉ số đúng và lợi nhuận trong hàng chục mili giây hoàn toàn có thể chấp nhận được.
Tuy nhiên, khi một số chuỗi chủ đề quan trọng (< = 40) bắt đầu thực hiện truy vấn này, hiệu suất trên nó xuống đến hàng chục giây.
Không có khóa trong cơ sở dữ liệu, không có truy vấn nào đang ghi dữ liệu vào các bảng này và nó tái tạo rất tốt với cơ sở dữ liệu được phân tách thực tế từ bất kỳ hoạt động nào khác. DB nằm trên cùng một máy vật lý và
máy không bị quá tải tại bất kỳ điểm nào, nghĩa là có nhiều CPU dự phòng, bộ nhớ và các tài nguyên khác
CPU bị quá tải bởi thao tác này.
Điều thực sự kỳ lạ là khi tôi thay thế cuộc gọi EF Any()
bằng Context.Database.ExecuteSqlCommand()
bằng SQL được sao chép (cũng sử dụng các tham số), vấn đề biến mất một cách kỳ diệu. Một lần nữa, điều này tái tạo rất đáng tin cậy - thay thế cuộc gọi Any()
với SQL được sao chép sẽ tăng hiệu suất theo 2-3 đơn đặt hàng của độ lớn.
Một hồ sơ đính kèm (dotTrace) lấy mẫu cho thấy rằng các chủ đề dường như tất cả dành thời gian của họ bằng phương pháp sau:
Có điều gì tôi đã bỏ lỡ hoặc chúng tôi đã trúng số ADO.NET/SQL Server cornercase?
bối cảnh nhiều hơn
Mã chạy truy vấn này là một công việc Hangfire. Với mục đích thử nghiệm, một tập lệnh xếp hàng rất nhiều công việc cần thực hiện và tối đa 40 chủ đề tiếp tục xử lý công việc. Mỗi công việc sử dụng một cá thể DbContext
riêng biệt và nó không thực sự được sử dụng nhiều. Có thêm một vài truy vấn trước và sau truy vấn có vấn đề và chúng mất thời gian dự kiến để thực thi.
Chúng tôi đang sử dụng nhiều công việc Hangfire khác nhau cho các mục đích tương tự và chúng hoạt động như mong đợi. Tương tự như thế này, trừ khi nó bị chậm dưới sự đồng thời cao (của cùng một công việc chính xác). Ngoài ra, chỉ cần chuyển sang SQL trên truy vấn cụ thể này sẽ khắc phục được sự cố.
Ảnh chụp nhanh hồ sơ ở trên là đại diện, tất cả các chuỗi đều làm chậm cuộc gọi phương thức cụ thể này và dành phần lớn thời gian của chúng trên đó.
CẬP NHẬT
tôi đang chạy lại rất nhiều những người kiểm tra cho sự tỉnh táo và các lỗi. Việc sao chép dễ dàng có nghĩa là nó vẫn còn trên một máy từ xa mà tôi không thể kết nối bằng cách sử dụng VS để gỡ lỗi.
Một trong các kiểm tra cho thấy rằng câu lệnh trước của tôi về CPU tự do là sai, CPU không hoàn toàn quá tải nhưng nhiều lõi trên thực tế đang chạy hết công suất trong suốt thời gian dài.
Kiểm tra lại mọi thứ một lần nữa và sẽ quay lại với nội dung cập nhật tại đây.
Phương thức đó chỉ chờ máy chủ trả lời. Nó không phải là lỗi. (Tôi không biết là gì.) – usr
Tại thời điểm chậm, hãy tạm dừng trình gỡ lỗi và chụp ảnh chụp màn hình cửa sổ Parallel Stacks. Chúng ta cần một mẫu những gì các chủ đề đang làm. – usr
Như đã nêu ở trên, trình bày hồ sơ đường dẫn nóng - tất cả các chủ đề chậm lại trên phương pháp này. Tôi nghi ngờ một trong hai trường hợp góc trong kết nối SQL hoặc có thể là một loạt các sự kiện gây ra SQL chính nó để chặn/làm chậm (ngay cả với các nguồn tài nguyên miễn phí). –