Trong các bài đăng của tôi năm nay, tôi đã thảo luận về phản ứng đầu gối với các kiểu chờ đợi khác nhau và trong bài đăng này, tôi sẽ tiếp tục với chủ đề thống kê chờ và thảo luận về PAGEIOLATCH_XX
Chờ đợi. Tôi nói "đợi đã" nhưng thực sự có nhiều loại PAGEIOLATCH
chờ đợi, mà tôi đã ký kết bằng XX ở cuối. Các ví dụ phổ biến nhất là:
-
PAGEIOLATCH_SH
- ( SH đang) chờ một trang tệp dữ liệu được đưa từ đĩa vào vùng đệm để có thể đọc nội dung của nó -
PAGEIOLATCH_EX
hoặcPAGEIOLATCH_UP
- ( EX lừa dối hoặc LÊN date) đợi một trang tệp dữ liệu được đưa từ đĩa vào vùng đệm để nội dung của nó có thể được sửa đổi
Trong số này, cho đến nay, loại phổ biến nhất là PAGEIOLATCH_SH
.
Khi kiểu chờ đợi này phổ biến nhất trên một máy chủ, phản ứng khó chịu là hệ thống con I / O phải có vấn đề và do đó, đó là nơi cần tập trung điều tra.
Điều đầu tiên cần làm là so sánh PAGEIOLATCH_SH
số lượng và thời gian chờ so với đường cơ sở của bạn. Nếu khối lượng các lần đợi nhiều hơn hoặc ít hơn như nhau, nhưng thời gian của mỗi lần chờ đọc trở nên lâu hơn nhiều, thì tôi sẽ lo lắng về sự cố hệ thống con I / O, chẳng hạn như:
- Cấu hình sai / sự cố ở cấp hệ thống con I / O
- Độ trễ mạng
- Một khối lượng công việc I / O khác gây ra tranh cãi với khối lượng công việc của chúng tôi
- Cấu hình sao chép / nhân bản hệ thống con I / O đồng bộ
Theo kinh nghiệm của tôi, mô hình thường là số lượng PAGEIOLATCH_SH
thời gian chờ đã tăng lên đáng kể so với số lượng cơ sở (bình thường) và thời gian chờ cũng tăng lên (tức là thời gian cho một I / O đọc đã tăng lên), bởi vì số lượng lớn các lần đọc làm quá tải hệ thống con I / O. Đây không phải là vấn đề hệ thống con I / O - đây là SQL Server thúc đẩy nhiều I / O hơn mức cần thiết. Trọng tâm bây giờ cần chuyển sang SQL Server để xác định nguyên nhân của I / Os bổ sung.
Nguyên nhân của Số lượng I / Os đã đọc
SQL Server có hai kiểu đọc:I / Os logic và I / Os vật lý. Khi phần Phương thức truy cập của Công cụ lưu trữ cần truy cập một trang, nó sẽ yêu cầu Nhóm đệm cho một con trỏ đến trang trong bộ nhớ (được gọi là I / O logic) và Nhóm đệm kiểm tra thông qua siêu dữ liệu của nó để xem liệu trang đó có đã có trong bộ nhớ.
Nếu trang nằm trong bộ nhớ, Nhóm đệm cung cấp con trỏ cho Phương thức truy cập và I / O vẫn là I / O hợp lý. Nếu trang không có trong bộ nhớ, Nhóm đệm sẽ cấp một I / O "thực" (được gọi là I / O vật lý) và luồng phải đợi nó hoàn tất - phát sinh PAGEIOLATCH_XX
Chờ đợi. Sau khi I / O hoàn tất và con trỏ khả dụng, luồng sẽ được thông báo và có thể tiếp tục chạy.
Trong một thế giới lý tưởng, toàn bộ khối lượng công việc của bạn sẽ nằm gọn trong bộ nhớ và vì vậy một khi vùng đệm đã "ấm lên" và chứa tất cả khối lượng công việc, không cần đọc nữa, chỉ ghi dữ liệu cập nhật. Tuy nhiên, đó không phải là một thế giới lý tưởng, và hầu hết các bạn không có được sự sang trọng đó, vì vậy một số lần đọc là không thể tránh khỏi. Miễn là số lần đọc vẫn ở mức cơ bản của bạn, không có vấn đề gì.
Khi một số lượng lớn các lần đọc được yêu cầu đột ngột và bất ngờ, đó là dấu hiệu cho thấy có sự thay đổi đáng kể trong khối lượng công việc, dung lượng bộ nhớ vùng đệm có sẵn để lưu trữ các bản sao của trang trong bộ nhớ hoặc cả hai.
Dưới đây là một số nguyên nhân gốc rễ có thể xảy ra (không phải là danh sách đầy đủ):
- Áp lực bộ nhớ ngoài của Windows lên SQL Server khiến trình quản lý bộ nhớ giảm kích thước vùng đệm
- Lên kế hoạch cho bộ nhớ đệm phình to khiến bộ nhớ bổ sung được mượn từ vùng đệm
- Một kế hoạch truy vấn thực hiện quét chỉ mục bảng / nhóm (thay vì tìm kiếm chỉ mục) vì:
- khối lượng công việc tăng lên
- một vấn đề về đánh giá thông số
- một chỉ mục không hợp nhất bắt buộc đã bị loại bỏ hoặc thay đổi
- một chuyển đổi ngầm định
Một mẫu cần tìm sẽ cho thấy nguyên nhân là quét bảng / chỉ mục theo cụm cũng là thấy một số lượng lớn CXPACKET
đợi cùng với PAGEIOLATCH_SH
chờ đợi. Đây là một mẫu phổ biến cho biết việc quét chỉ mục theo nhóm / bảng lớn, song song đang diễn ra.
Trong mọi trường hợp, bạn có thể xem kế hoạch truy vấn nào đang gây ra PAGEIOLATCH_SH
đợi bằng sys.dm_os_waiting_tasks
và các DMV khác, và bạn có thể nhận mã để thực hiện điều đó trong bài đăng trên blog của tôi tại đây. Nếu bạn có sẵn công cụ giám sát của bên thứ ba, nó có thể giúp bạn xác định thủ phạm mà không làm bạn bẩn tay.
Quy trình làm việc mẫu với SQL Sentry và Plan Explorer
Trong một ví dụ đơn giản (rõ ràng là có nội dung), hãy giả sử rằng tôi đang sử dụng hệ thống khách hàng sử dụng bộ công cụ của SQL Sentry và thấy lượng I / O chờ tăng đột biến trong chế độ xem bảng điều khiển của SQL Sentry, như được hiển thị bên dưới:
Phát hiện thấy I / O chờ tăng đột biến trong SQL Sentry
Tôi quyết định điều tra bằng cách nhấp chuột phải vào một khoảng thời gian đã chọn xung quanh thời điểm tăng đột biến, sau đó chuyển sang chế độ xem SQL Hàng đầu, sẽ hiển thị cho tôi các truy vấn đắt nhất đã được thực thi:
Đánh dấu phạm vi thời gian và điều hướng đến SQL hàng đầu
Trong chế độ xem này, tôi có thể xem truy vấn I / O chạy dài hoặc cao nào đang chạy tại thời điểm tăng đột biến xảy ra và sau đó chọn đi sâu vào kế hoạch truy vấn của chúng (trong trường hợp này, chỉ có một truy vấn chạy dài, chạy trong gần một phút):
Xem xét truy vấn chạy dài trong SQL hàng đầu
Nếu tôi nhìn vào kế hoạch trong máy khách SQL Sentry hoặc mở nó trong SQL Sentry Plan Explorer, tôi ngay lập tức thấy nhiều vấn đề. Số lần đọc được yêu cầu để trả về 7 hàng dường như quá cao, khoảng cách giữa các hàng ước tính và thực tế là lớn và kế hoạch cho thấy quá trình quét chỉ mục xảy ra ở nơi tôi mong đợi một tìm kiếm:
Xem các cảnh báo chuyển đổi ngầm trong kế hoạch truy vấn
Nguyên nhân của tất cả điều này được đánh dấu trong cảnh báo trên SELECT
toán tử: Đó là một chuyển đổi ngầm định!
Chuyển đổi ngầm định là một vấn đề khó xảy ra do sự không khớp giữa kiểu dữ liệu của vị từ tìm kiếm và kiểu dữ liệu của cột đang được tìm kiếm hoặc một phép tính đang được thực hiện trên cột của bảng chứ không phải là vị từ tìm kiếm. Trong cả hai trường hợp, SQL Server không thể sử dụng tìm kiếm chỉ mục trên cột bảng và thay vào đó phải sử dụng quét.
Điều này có thể xuất hiện trong mã dường như vô tội và một ví dụ phổ biến là sử dụng phép tính ngày. Nếu bạn có một bảng lưu trữ độ tuổi của khách hàng và bạn muốn thực hiện phép tính để xem hôm nay có bao nhiêu người từ 21 tuổi trở lên, bạn có thể viết mã như sau:
WHERE DATEADD (YEAR, 21, [MyTable].[BirthDate]) <= @today;
Với mã này, phép tính nằm trên cột của bảng và do đó không thể sử dụng tìm kiếm chỉ mục, dẫn đến một biểu thức không thể tìm thấy (về mặt kỹ thuật được gọi là biểu thức không phải SARGable) và quét chỉ mục bảng / nhóm. Điều này có thể được giải quyết bằng cách chuyển phép tính sang phía bên kia của toán tử:
WHERE [MyTable].[BirthDate] <= DATEADD (YEAR, -21, @today);
Về vấn đề khi so sánh cột cơ bản yêu cầu chuyển đổi kiểu dữ liệu có thể gây ra chuyển đổi ngầm, đồng nghiệp của tôi Jonathan Kehayias đã viết một bài đăng blog tuyệt vời so sánh mọi sự kết hợp của các loại dữ liệu và lưu ý khi cần chuyển đổi ngầm.
Tóm tắt
Đừng rơi vào bẫy khi nghĩ rằng PAGEIOLATCH_XX
quá nhiều sự chờ đợi do hệ thống con I / O gây ra. Theo kinh nghiệm của tôi, chúng thường gây ra bởi một số vấn đề liên quan đến SQL Server và đó là nơi tôi bắt đầu khắc phục sự cố.
Về số liệu thống kê chờ chung có liên quan, bạn có thể tìm thêm thông tin về cách sử dụng chúng để khắc phục sự cố hiệu suất trong:
- Loạt bài đăng trên blog SQLskills của tôi, bắt đầu với số liệu thống kê Chờ hoặc vui lòng cho tôi biết mức độ ảnh hưởng của nó
- Thư viện Các loại Chờ đợi và Lớp Chốt của tôi tại đây
- Khóa đào tạo trực tuyến Pluralsight của tôi SQL Server:Khắc phục sự cố về hiệu suất sử dụng thống kê chờ
- SQL Sentry
Trong phần tiếp theo của loạt bài này, tôi sẽ thảo luận về một kiểu chờ đợi khác là nguyên nhân phổ biến của phản ứng giật đầu gối. Cho đến lúc đó, chúc bạn khắc phục sự cố!