Tôi đã cố gắng chẩn đoán sự chậm chạp trong một ứng dụng. Đối với điều này, tôi đã đăng nhập các sự kiện mở rộng của SQL Server .
- Đối với câu hỏi này, tôi đang xem xét một thủ tục được lưu trữ cụ thể.
- Nhưng có một tập hợp cốt lõi của một tá các thủ tục được lưu trữ có thể được sử dụng như một cuộc điều tra táo với táo
- và bất cứ khi nào tôi tự chạy một trong các thủ tục được lưu trữ, nó luôn chạy nhanh
- và nếu người dùng thử lại: nó sẽ chạy nhanh.
Thời gian thực hiện của thủ tục được lưu trữ rất khác nhau. Rất nhiều thực thi của thủ tục được lưu trữ này trả về trong <1s:
Và đối với cái xô "nhanh" đó, nó ít hơn 1 giây. Nó thực sự khoảng 90 ms:
Nhưng có một cái đuôi dài của người dùng phải chờ 2 giây, 3 giây, 4 giây. Một số phải chờ 12, 13, 14. Sau đó, có những linh hồn thực sự đáng thương, những người phải chờ 22, 23, 24.
Và sau 30 giây, ứng dụng khách bỏ cuộc, hủy bỏ truy vấn và người dùng phải đợi 30 giây .
Tương quan để tìm nhân quả
Vì vậy, tôi đã cố gắng để tương quan:
- thời lượng so với đọc hợp lý
- thời lượng so với đọc vật lý
- thời lượng so với thời gian cpu
Và dường như không có bất kỳ mối tương quan nào; dường như không có nguyên nhân
thời lượng so với số lần đọc logic : dù là một ít hay nhiều lần đọc logic, thời lượng vẫn dao động dữ dội :
thời lượng so với đọc vật lý : ngay cả khi truy vấn không được cung cấp từ bộ đệm và rất nhiều lần đọc vật lý là cần thiết, nó không ảnh hưởng đến thời lượng:
thời lượng so với thời gian cpu : Cho dù truy vấn mất 0 giây thời gian CPU hay 2,5 giây thời gian CPU đầy đủ, thời lượng có cùng một biến thiên:
Phần thưởng : Tôi nhận thấy rằng Thời lượng v Vật lý đọc và Thời lượng v Thời gian CPU trông rất giống nhau. Điều này được chứng minh nếu tôi cố gắng tương quan thời gian của CPU với Đọc vật lý:
Hóa ra rất nhiều việc sử dụng CPU đến từ I / O. Ai biết!
Vì vậy, nếu không có gì về hành động thực hiện truy vấn có thể giải thích cho sự khác biệt về thời gian thực hiện, thì điều đó có nghĩa là đó là một cái gì đó không liên quan đến CPU hoặc ổ cứng?
Nếu CPU hoặc ổ cứng là nút cổ chai; nó sẽ không phải là nút cổ chai?
Nếu chúng ta đưa ra giả thuyết rằng đó là CPU là nút cổ chai; CPU được cung cấp năng lượng cho máy chủ này:
- Sau đó, việc thực thi sử dụng nhiều thời gian CPU sẽ mất nhiều thời gian hơn?
- vì họ phải hoàn thành với những người khác sử dụng CPU quá tải?
Tương tự cho các ổ đĩa cứng. Nếu chúng ta đưa ra giả thuyết rằng ổ cứng là một nút cổ chai; rằng các ổ đĩa cứng không có đủ thông qua ngẫu nhiên cho máy chủ này:
- sau đó sẽ không thực hiện bằng cách sử dụng đọc vật lý nhiều hơn mất nhiều thời gian?
- vì họ phải hoàn thành với những người khác bằng cách sử dụng I / O ổ cứng quá tải?
Các thủ tục được lưu trữ tự nó không thực hiện, cũng không yêu cầu, bất kỳ ghi.
- Thông thường nó trả về 0 hàng (90%).
- Thỉnh thoảng nó sẽ trả về 1 hàng (7%).
- Hiếm khi nó sẽ trả về 2 hàng (1,4%).
- Và trong trường hợp xấu nhất, nó đã trả về hơn 2 hàng (một lần trả lại 12 hàng)
Vì vậy, nó không giống như nó trả lại một khối lượng dữ liệu điên rồ.
Sử dụng CPU máy chủ
Mức sử dụng bộ xử lý của máy chủ trung bình khoảng 1,8%, với mức tăng đột biến lên tới 18% - vì vậy có vẻ như tải CPU là một vấn đề:
Vì vậy, CPU máy chủ dường như không bị quá tải.
Nhưng máy chủ là ảo ...
Một cái gì đó bên ngoài vũ trụ?
Điều duy nhất còn lại tôi có thể tưởng tượng là thứ gì đó tồn tại bên ngoài vũ trụ của máy chủ.
- nếu nó không hợp lý đọc
- và nó không phải là đọc vật lý
- và nó không sử dụng cpu
- và nó không tải CPU
Và nó không giống như các tham số cho thủ tục được lưu trữ (vì đưa ra cùng một truy vấn theo cách thủ công và không mất 27 giây - mất ~ 0 giây).
Những gì khác có thể chiếm cho máy chủ đôi khi mất 30 giây, thay vì 0 giây, để chạy cùng một quy trình được lưu trữ được biên dịch.
- trạm kiểm soát?
Nó là một máy chủ ảo
- Máy chủ quá tải?
- VM khác trên cùng một máy chủ?
Đi qua các sự kiện mở rộng của máy chủ; không có gì khác đặc biệt xảy ra khi một truy vấn đột nhiên mất 20 giây. Nó chạy tốt, sau đó quyết định không chạy tốt:
- 2 giây
- 1 giây
- 30 giây
- 3 giây
- 2 giây
Và không có vật phẩm vất vả nào khác tôi có thể tìm thấy. Đó không phải là trong mỗi bản sao lưu nhật ký giao dịch 2 giờ.
Nó có thể là gì khác?
Có điều gì tôi có thể nói ngoài: "máy chủ" không?
Chỉnh sửa : Tương quan theo thời gian trong ngày
Tôi nhận ra tôi đã tương quan thời lượng với mọi thứ:
- đọc logic
- đọc vật lý
- sử dụng CPU
Nhưng điều duy nhất tôi không liên quan đến nó là thời gian trong ngày . Có lẽ sao lưu nhật ký giao dịch cứ sau 2 giờ là một vấn đề.
Hoặc có lẽ là chậm làm xảy ra trong các ngăn trong trạm kiểm soát?
Không
Intel Xeon Gold Quad-core 6142.
Chỉnh sửa - Mọi người đang giả định kế hoạch thực hiện truy vấn
Mọi người đang đưa ra giả thuyết về kế hoạch thực hiện truy vấn phải khác nhau giữa "nhanh" và "chậm". Họ không phải.
Và chúng ta có thể thấy điều này ngay lập tức từ kiểm tra.
Chúng tôi biết thời lượng câu hỏi dài hơn không phải vì kế hoạch thực hiện "kém":
- một bài đọc hợp lý hơn
- một CPU tiêu thụ nhiều CPU hơn từ nhiều lần tham gia và tra cứu khóa
Bởi vì nếu việc tăng đọc hoặc tăng CPU là nguyên nhân của thời lượng truy vấn tăng lên, thì chúng ta đã thấy điều đó ở trên. Không có mối tương quan.
Nhưng hãy thử tương quan thời lượng với chỉ số sản phẩm của khu vực đọc CPU:
Thậm chí còn trở nên ít hơn về một mối tương quan - đó là một nghịch lý.
Chỉnh sửa : Đã cập nhật sơ đồ phân tán để khắc phục lỗi trong các biểu đồ phân tán Excel với số lượng lớn các giá trị.
Bước tiếp theo
Các bước tiếp theo của tôi sẽ là khiến ai đó phải tạo máy chủ để tạo các sự kiện cho các truy vấn bị chặn - sau 5 giây:
EXEC sp_configure 'blocked process threshold', '5';
RECONFIGURE
Nó sẽ không giải thích nếu các truy vấn bị chặn trong 4 giây. Nhưng có lẽ bất cứ điều gì chặn truy vấn trong 5 giây cũng chặn một số trong 4 giây.
Máy quay chậm
Đây là kế hoạch chậm của hai thủ tục được lưu trữ đang được thực thi:
- `EXECUTE FindFrob @CustomerID = 7383, @StartDate = '20190725 04: 00: 00.000', @EndDate = '20190726 04: 00: 00.000'
- `EXECUTE FindFrob @CustomerID = 7383, @StartDate = '20190725 04: 00: 00.000', @EndDate = '20190726 04: 00: 00.000'
Quy trình được lưu trữ tương tự, với cùng các tham số, chạy ngược lại:
| Duration (us) | CPU time (us) | Logical reads | Physical reads |
|---------------|---------------|---------------|----------------|
| 13,984,446 | 47,000 | 5,110 | 771 |
| 4,603,566 | 47,000 | 5,126 | 740 |
Gọi 1:
|--Nested Loops(Left Semi Join, OUTER REFERENCES:([Contoso2].[dbo].[Frobs].[FrobGUID]) OPTIMIZED)
|--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]))
| |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[RowNumber]) OPTIMIZED)
| | |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
| | | |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
| | | | |--Index Seek(OBJECT:([Contoso2].[dbo].[TransactionPatronInfo].[IX_TransactionPatronInfo_CustomerID_TransactionGUID] AS [tpi]), SEEK:([tpi].[CustomerID]=[@CustomerID]) ORDERED FORWARD)
| | | | |--Index Seek(OBJECT:([Contoso2].[dbo].[Transactions].[IX_Transactions_TransactionGUIDTransactionDate]), SEEK:([Contoso2].[dbo].[Transactions].[TransactionGUID]=[Contoso2].[dbo
| | | |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions2_MoneyAppearsOncePerTransaction]), SEEK:([Contoso2].[dbo].[FrobTransactions].[TransactionGUID]=[Contos
| | |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions_RowNumber]), SEEK:([Contoso2].[dbo].[FrobTransactions].[RowNumber]=[Contoso2].[dbo].[Fin
| |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[Frobs].[PK_Frobs_FrobGUID]), SEEK:([Contoso2].[dbo].[Frobs].[FrobGUID]=[Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]), WHERE:([Contos
|--Filter(WHERE:([Expr1009]>(1)))
|--Compute Scalar(DEFINE:([Expr1009]=CONVERT_IMPLICIT(int,[Expr1012],0)))
|--Stream Aggregate(DEFINE:([Expr1012]=Count(*)))
|--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactins_OnFrobGUID]), SEEK:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]=[Contoso2].[dbo].[Frobs].[LC
Gọi 2
|--Nested Loops(Left Semi Join, OUTER REFERENCES:([Contoso2].[dbo].[Frobs].[FrobGUID]) OPTIMIZED)
|--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]))
| |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[RowNumber]) OPTIMIZED)
| | |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
| | | |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
| | | | |--Index Seek(OBJECT:([Contoso2].[dbo].[TransactionPatronInfo].[IX_TransactionPatronInfo_CustomerID_TransactionGUID] AS [tpi]), SEEK:([tpi].[CustomerID]=[@CustomerID]) ORDERED FORWARD)
| | | | |--Index Seek(OBJECT:([Contoso2].[dbo].[Transactions].[IX_Transactions_TransactionGUIDTransactionDate]), SEEK:([Contoso2].[dbo].[Transactions].[TransactionGUID]=[Contoso2].[dbo
| | | |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions2_MoneyAppearsOncePerTransaction]), SEEK:([Contoso2].[dbo].[FrobTransactions].[TransactionGUID]=[Contos
| | |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions_RowNumber]), SEEK:([Contoso2].[dbo].[FrobTransactions].[RowNumber]=[Contoso2].[dbo].[Fin
| |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[Frobs].[PK_Frobs_FrobGUID]), SEEK:([Contoso2].[dbo].[Frobs].[FrobGUID]=[Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]), WHERE:([Contos
|--Filter(WHERE:([Expr1009]>(1)))
|--Compute Scalar(DEFINE:([Expr1009]=CONVERT_IMPLICIT(int,[Expr1012],0)))
|--Stream Aggregate(DEFINE:([Expr1012]=Count(*)))
|--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactins_OnFrobGUID]), SEEK:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]=[Contoso2].[dbo].[Frobs].[LC
Nó có ý nghĩa cho các kế hoạch là giống hệt nhau; nó đang thực hiện cùng một thủ tục được lưu trữ, với cùng các tham số.