Lời nói đầu
Có một hệ thống thông tin do tôi quản lý. Hệ thống bao gồm các thành phần sau:
1. Cơ sở dữ liệu MS SQL Server
2. Ứng dụng máy chủ
3. Ứng dụng khách
Các hệ thống thông tin này được cài đặt trên một số đối tượng. Hệ thống thông tin được sử dụng tích cực 24/24 giờ cho mỗi đối tượng từ 2 đến 20 người sử dụng cùng một lúc. Do đó, bạn không thể thực hiện bảo trì định kỳ cùng một lúc. Vì vậy, tôi phải «lây lan» chống phân mảnh chỉ mục SQL Server trong suốt cả ngày, thay vì chống phân mảnh tất cả các chỉ mục bị phân mảnh cần thiết trong một lần thực hiện. Điều này cũng áp dụng cho các hoạt động khác.
Thuộc tính tự động cập nhật thống kê được đặt trong thuộc tính của cơ sở dữ liệu. Bên cạnh đó, số liệu thống kê được cập nhật trên chỉ mục chống phân mảnh.
Vấn đề
Khoảng một năm trước, tôi gặp phải sự cố sau:
Đôi khi, tất cả các truy vấn đều chạy chậm. Đáng chú ý, thời gian trễ là ngẫu nhiên. Nó xảy ra trên mọi đối tượng vào một ngày ngẫu nhiên. Hơn nữa, khi tôi bắt đầu phân tích tần suất xảy ra chậm trễ (bằng cách sử dụng trình mô tả), tôi phát hiện ra rằng chúng xảy ra hàng ngày vào một thời điểm ngẫu nhiên. Người dùng không phải lúc nào cũng chú ý đến chúng mà chỉ coi chúng là độ trễ ngẫu nhiên duy nhất và sau đó hệ thống hoạt động nhanh chóng trở lại.
Giải quyết vấn đề
Tôi đã xem xét tất cả các truy vấn chạy chậm. Điều kỳ lạ nhất là tất cả các truy vấn đều chạy chậm vào một thời điểm ngẫu nhiên, ngay cả những truy vấn đơn giản nhất, như kéo bản ghi cuối cùng từ một bảng có hàng nghìn hàng.
Hơn nữa, tôi đã thực hiện các bước sau:
1. Tôi đã phân tích nhật ký MS SQL Server và Windows Server, nhưng không thể tìm ra nguyên nhân của sự chậm trễ.
2. Tôi đã phân tích các chỉ mục (phân mảnh, v.v.), thêm các chỉ mục còn thiếu và loại bỏ các chỉ mục không sử dụng.
3. Tôi đã phân tích các truy vấn - một số truy vấn đã được cải thiện.
4. Tôi đã phân tích các tác vụ trong SQL Agent và không thể liên kết các tác vụ với sự cố trễ.
5. Tôi đã phân tích các nhiệm vụ trong Task Scheduler và không thể liên kết các nhiệm vụ với vấn đề chậm trễ.
6. Hồ sơ cho thấy kết quả, nhưng không phải là nguyên nhân của sự chậm trễ.
7. Tôi đã thực hiện kiểm tra các lần chặn - không có lần chặn dài nào được tiết lộ.
Kết quả là, tôi đã dành hơn 3 tháng cho việc tìm kiếm không thành công với lý do thỉnh thoảng truy vấn chạy chậm. Tuy nhiên, tôi đã tiết lộ một sự thật thú vị - thay vì chỉ báo Thực thi Công nhân, chỉ báo Chờ đã qua tăng cho tất cả các truy vấn. Thực tế này đã cho tôi ý tưởng rằng có điều gì đó không ổn với các đĩa. Tôi đã kiểm tra chúng - mọi thứ đều ổn.
Giải pháp
Trước sự ngạc nhiên của tôi, tôi đã vô tình tiết lộ rằng khi một truy vấn được thực thi chậm trong ứng dụng, nó chạy nhanh trong SSMS. Một bài báo đã giúp giải quyết vấn đề (ít nhất nó đã gợi ý ý tưởng).
Một đoạn từ bài báo:
Trong thực tế, tùy chọn SET quan trọng nhất là ARITHABORT, vì giá trị mặc định cho tùy chọn này khác nhau đối với các ứng dụng và đối với SQL Server Management Studio. Điều này giải thích tại sao bạn có thể phát hiện một truy vấn chạy chậm trong ứng dụng của mình và sau đó có được tốc độ tốt bằng cách thực thi nó trong SSMS. Ứng dụng sử dụng một kế hoạch đã được xây dựng cho một tập hợp các giá trị khác với các giá trị chính xác thực tế. Trong khi nếu bạn chạy truy vấn trong SSMS, rất có thể bộ nhớ đệm chưa có kế hoạch thực thi cho ARITHABORT ON và do đó SQL Server sẽ xây dựng kế hoạch cho các giá trị hiện tại của bạn.
Sự khác biệt trong việc thực thi là do tham số SET ARITHABORT. Đối với tất cả các truy vấn được thực thi trong SSMS, tùy chọn này được bật và đối với các truy vấn từ bên ngoài (từ các ứng dụng) - bị vô hiệu hóa. Nó không thể được bật ngay cả bằng một truy vấn đơn giản cho các ứng dụng:
SET ARITHABORT ON;
Sau đó là một ý tưởng điên rồ - xóa bộ nhớ đệm theo thủ tục tại thời điểm treo máy.
Để kiểm tra thủ công tiếp theo, tôi cần viết câu lệnh sau trước truy vấn trong SSMS:
SET ARITHABORT OFF;
Như vậy chúng ta sẽ mô phỏng hoạt động của ứng dụng. Khi truy vấn đã chạy trong một thời gian dài, tôi đã xóa bộ đệm ẩn thủ tục. Và điều này luôn có ích. Trước khi xóa bộ đệm theo thủ tục, truy vấn có thể chạy tối đa 20-30 giây và sau đó - 0 giây.
Sau đó, tôi thực hiện một thử nghiệm khác - làm sạch toàn bộ bộ đệm thủ tục cho toàn bộ cơ sở dữ liệu mỗi giờ thông qua SQL Agent:
--cleaning the cache by database id DBCC FLUSHPROCINDB (@db_id);
Sau đó, tất cả các truy vấn chạy rất nhanh (dưới 0,05 giây). Chỉ có một số lần thực thi tối đa 5-10 giây nhưng người dùng không nhận thấy bất kỳ lỗi treo máy nào. Hơn nữa, việc cập nhật số liệu thống kê không cải thiện kết quả, vì vậy tôi đã tắt cập nhật số liệu thống kê.
Sau một vài tháng nghiên cứu nữa, tôi phát hiện ra rằng thỉnh thoảng xảy ra lỗi treo khi bộ nhớ cache tiêu thụ mọi thứ trên máy chủ và không còn dung lượng trống hoặc có bộ nhớ trống nhưng dưới 1 GB RAM hoặc dịch vụ MS SQL Server chiếm tất cả RAM được phân bổ (thông qua Trình quản lý tác vụ). Nhưng sự kiện thứ hai chỉ xảy ra hai lần trong toàn bộ nghiên cứu.
Thực tế là mọi thứ đều được ghi vào bộ nhớ đệm theo nghĩa đen, trong khi bộ nhớ đệm không phải lúc nào cũng được giải phóng đúng hạn. Sự cố với bộ nhớ cache đã được giải quyết bằng cách sử dụng chương trình EmptyStandbyList.exe.
Tôi đã định cấu hình ứng dụng này thông qua Task Scheduler để chạy 1 lần mỗi giờ. Sau tất cả công việc đã hoàn thành, không có vấn đề nào bị treo trên tất cả các đối tượng trong hơn nửa năm nay.
Điều duy nhất vẫn chưa rõ ràng là các trường hợp hiếm khi một truy vấn bị treo trong 5-10 giây mỗi tháng một lần vào một ngày ngẫu nhiên và vào một thời điểm ngẫu nhiên. Có 4 trường hợp như vậy và chỉ xảy ra trên hai đối tượng trong nửa năm khi dịch vụ MS SQL Server chiếm tất cả bộ nhớ được cấp phát trong một khoảng thời gian ngắn.
Về cơ bản, không cần phải tìm hiểu sâu hơn, vì người dùng không nhận thấy bất kỳ lỗi treo máy nào và mọi thứ hoạt động tốt, nhưng nếu ai có bất kỳ suy nghĩ nào, tôi sẽ rất biết ơn vì đã chia sẻ.
Bài viết này được viết để giúp những người gặp phải những vấn đề như vậy, vì tôi không tìm thấy câu trả lời toàn diện trên Internet, và tôi đã dành rất nhiều thời gian để nghiên cứu vấn đề và tìm ra giải pháp.
Xem thêm:
- Triển khai Chỉ báo Hiệu suất Máy chủ SQL cho các Truy vấn, Thủ tục được Lưu trữ và Trình kích hoạt
- Tự động chống phân mảnh chỉ mục trong cơ sở dữ liệu MS SQL Server
Công cụ hữu ích:
dbForge Query Builder dành cho SQL Server - cho phép người dùng tạo các truy vấn SQL phức tạp một cách nhanh chóng và dễ dàng thông qua giao diện trực quan trực quan mà không cần viết mã thủ công.