SQL Server 2016 Bad Query Plan khóa DB mỗi tuần một lần


16

Mỗi tuần một lần, trong 5 tuần qua, vào cùng một thời điểm trong ngày (sáng sớm, có thể dựa trên hoạt động của người dùng khi mọi người bắt đầu sử dụng nó), SQL Server 2016 (AWS RDS, được nhân đôi) bắt đầu hết thời gian truy vấn.

CẬP NHẬT THỐNG KÊ trên tất cả các bảng luôn sửa nó ngay lập tức.

Sau lần đầu tiên, tôi đã làm cho nó cập nhật tất cả các số liệu thống kê trên tất cả các bảng hàng đêm (thay vì hàng tuần), nhưng nó vẫn xảy ra, (khoảng 8 giờ sau khi thống kê cập nhật chạy, nhưng không phải mỗi ngày nó chạy).

Lần cuối cùng này, tôi đã kích hoạt Cửa hàng truy vấn để xem liệu tôi có thể tìm thấy kế hoạch truy vấn / truy vấn cụ thể nào không. Tôi nghĩ rằng tôi đã có thể thu hẹp nó xuống một:

Kế hoạch truy vấn xấu

Sau khi tìm thấy truy vấn đó, tôi đã thêm một chỉ mục được đề xuất bị thiếu trong truy vấn không được sử dụng thường xuyên này (nhưng nó chạm vào rất nhiều bảng được sử dụng thường xuyên).

Kế hoạch truy vấn xấu đã thực hiện Quét chỉ mục (trên một bảng chỉ có 10k hàng). Các kế hoạch truy vấn khác được trả về tính bằng mili giây, được sử dụng để thực hiện quét tương tự. Kế hoạch truy vấn mới nhất, sau khi tạo chỉ mục mới chỉ tìm kiếm. Nhưng ngay cả khi không có chỉ số đó, 99% thời gian, nó sẽ quay trở lại trong vòng vài mili giây, nhưng sau đó, hàng tuần, sẽ mất> 40 giây.

Điều này bắt đầu xảy ra sau khi chuyển sang SQL Server 2016 từ năm 2012.

DBCC CHECKDB trả về không có lỗi.

  1. Chỉ số mới sẽ khắc phục vấn đề, khiến nó không bao giờ chọn kế hoạch xấu nữa?
  2. Tôi có nên "buộc" kế hoạch hoạt động tốt bây giờ không?
  3. Làm cách nào để đảm bảo điều này không xảy ra với truy vấn / kế hoạch khác?
  4. Đây có phải là một triệu chứng của một vấn đề lớn hơn?

Các chỉ mục tôi vừa thêm:

CREATE NONCLUSTERED INDEX idx_AppointmetnAttendee_AttendeeType
ON [dbo].[AppointmentAttendee] ([UserID],[AttendeeType])

CREATE NONCLUSTERED INDEX [idx_appointment_start] ON [dbo].[Appointment]
(
    [ProjectID] ASC,
    [Start] ASC
)
INCLUDE (   [ID],
    [AllDay],
    [End],
    [Location],
    [Notes],
    [Title],
    [CreatedByID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

Toàn văn truy vấn:

https://pastebin.com/Z5szPBfu (LINQ tạo, tôi có thể / nên có thể tối ưu hóa cột được lựa chọn, nhưng nó phải là không liên quan đến vấn đề này)


Tôi chỉ nhận thấy rằng việc quét các kế hoạch trước đó không hết thời gian là ở một bảng khác, có cùng kích thước. Cuộc hẹn: 11931 hàng, Cuộc hẹnAttendee: 11937 hàng.
Tên âm thanh chuyên nghiệp

Câu trả lời:


16

Tôi sẽ trả lời câu hỏi của bạn theo thứ tự khác với câu hỏi của bạn.

4. Đây có phải là triệu chứng của một vấn đề lớn hơn?

Công cụ ước tính cardinality mới trong SQL Server 2016 có thể góp phần gây ra sự cố. SQL Server 2012 sử dụng CE kế thừa và bạn không gặp phải sự cố của mình trên phiên bản đó. Công cụ ước tính cardinality mới đưa ra các giả định khác nhau về dữ liệu của bạn và có thể tạo các gói truy vấn khác nhau cho cùng một SQL. Bạn có thể trải nghiệm hiệu suất tốt hơn cho một số truy vấn với CE kế thừa tùy thuộc vào truy vấn và dữ liệu của bạn. Vì vậy, một số phần trong mô hình dữ liệu của bạn có thể không phù hợp nhất với CE mới. Điều đó không sao, nhưng bây giờ bạn có thể cần phải làm việc xung quanh CE mới.

Tôi cũng sẽ quan tâm đến hiệu suất truy vấn không nhất quán ngay cả với các cập nhật thống kê hàng ngày. Một điều quan trọng cần lưu ý là việc thu thập số liệu thống kê trên tất cả các bảng sẽ xóa sạch tất cả các gói truy vấn khỏi bộ đệm, do đó bạn có thể gặp vấn đề với số liệu thống kê hoặc có thể phải thực hiện với việc đánh hơi tham số. Thật khó để đưa ra quyết định nếu không có nhiều thông tin về mô hình dữ liệu, tốc độ thay đổi dữ liệu, chính sách cập nhật thống kê, cách bạn gọi mã của mình, v.v. SQL Server 2016 cung cấp một số cài đặt mức cơ sở dữ liệu để đánh hơi tham số có thể hữu ích , nhưng điều đó có thể ảnh hưởng đến toàn bộ ứng dụng của bạn thay vì chỉ một truy vấn có vấn đề.

Tôi sẽ đưa ra một kịch bản ví dụ có thể dẫn đến hành vi này. Bạn đã nói:

Một số người dùng có thể có 1 hồ sơ cấp phép, một số, lên tới 20k.

Giả sử bạn thu thập số liệu thống kê trên tất cả các bảng sẽ xóa sạch tất cả các gói truy vấn. Tùy thuộc vào các yếu tố được đề cập ở trên, nếu truy vấn đầu tiên trong ngày đối với người dùng chỉ có 1 bản ghi quyền thì SQL Server có thể lưu trữ một gói hoạt động tốt cho người dùng có 1 bản ghi nhưng hoạt động khủng khiếp với người dùng có 20k bản ghi. Nếu truy vấn đầu tiên trong ngày là chống lại người dùng có hồ sơ 20k thì bạn có thể nhận được một kế hoạch tốt cho hồ sơ 20k. Khi mã được chạy với người dùng có 1 bản ghi, nó có thể không phải là truy vấn tối ưu nhất nhưng nó vẫn có thể kết thúc sau ms. Nó thực sự có âm thanh như đánh hơi tham số. Nó giải thích lý do tại sao bạn không luôn thấy vấn đề hoặc tại sao đôi khi phải mất hàng giờ để hiển thị.

1. Chỉ số mới sẽ khắc phục vấn đề, khiến nó không bao giờ chọn kế hoạch xấu nữa?

Tôi nghĩ rằng một trong những chỉ mục mà bạn đã thêm sẽ ngăn chặn sự cố vì việc truy cập dữ liệu cần thiết thông qua chỉ mục sẽ rẻ hơn so với thực hiện quét chỉ mục theo cụm, đặc biệt là khi quá trình quét không thể kết thúc sớm. Hãy phóng to phần xấu của kế hoạch truy vấn:

kế hoạch truy vấn xấu

SQL Server ước tính rằng chỉ một hàng sẽ được trả về từ tham gia [Permission][Project]. Đối với mỗi hàng trong đầu vào bên ngoài, nó sẽ thực hiện quét chỉ mục theo cụm [Appointment]. Tất cả các hàng sẽ được quét từ bảng này, nhưng chỉ những hàng khớp với bộ lọc trên [Start]mới được trả về cho toán tử nối. Trong toán tử tham gia kết quả được giảm thêm.

Kế hoạch truy vấn được mô tả ở trên có thể ổn nếu thực sự chỉ có một hàng được gửi đến đầu vào bên ngoài của phép nối. Tuy nhiên, nếu ước tính cardinality từ liên kết là sai và chúng tôi nhận được, giả sử, 1000 hàng, thì SQL Server sẽ thực hiện quét 1000 chỉ mục cụm [Appointment]. Hiệu suất của kế hoạch truy vấn rất nhạy cảm với các vấn đề ước tính.

Cách trực tiếp nhất để không bao giờ có được kế hoạch truy vấn đó nữa là tạo một chỉ mục bao phủ so với [Appointment]bảng. Một cái gì đó giống như một chỉ số trên [ProjectId][Start]nên làm điều đó. Có vẻ như đây chính xác là [idx_appointment_start]chỉ mục mà bạn đã tạo để giải quyết vấn đề. Một cách khác để làm nản lòng SQL server từ chọn kế hoạch truy vấn là để sửa chữa ước tính cardinality từ tham gia vào [Permission][Project]. Các cách điển hình để thực hiện điều đó bao gồm thay đổi mã, cập nhật số liệu thống kê, sử dụng CE kế thừa, tạo số liệu thống kê nhiều cột, cung cấp cho SQL Server thêm thông tin về các biến cục bộ như với một RECOMPILEgợi ý hoặc cụ thể hóa các hàng đó vào bảng tạm thời. Nhiều trong số các kỹ thuật đó không phải là một cách tiếp cận tốt khi bạn cần thời gian phản hồi ở mức ms hoặc phải viết mã thông qua ORM.

Chỉ mục mà bạn đã tạo [AppointmentAttendee]không phải là cách trực tiếp để giải quyết vấn đề. Tuy nhiên, bạn sẽ nhận được số liệu thống kê nhiều cột trên chỉ mục và những thống kê đó có thể ngăn cản kế hoạch truy vấn xấu. Chỉ mục có thể cung cấp một cách hiệu quả hơn để truy cập dữ liệu cũng có thể ngăn cản kế hoạch truy vấn xấu, nhưng tôi không nghĩ có bất kỳ loại đảm bảo nào rằng nó sẽ không xảy ra nữa chỉ với chỉ mục trên [AppointmentAttendee].

3. Làm cách nào để đảm bảo điều này không xảy ra với truy vấn / kế hoạch khác?

Tôi hiểu lý do tại sao bạn hỏi câu hỏi này nhưng nó là một câu hỏi cực kỳ rộng. Lời khuyên duy nhất của tôi là cố gắng hiểu rõ hơn nguyên nhân gốc rễ của sự không ổn định của kế hoạch truy vấn, để xác thực rằng bạn có các chỉ mục phù hợp được tạo cho khối lượng công việc của mình và kiểm tra cẩn thận và theo dõi khối lượng công việc của bạn. Microsoft có một số lời khuyên chung về cách xử lý các hồi quy kế hoạch truy vấn gây ra bởi CE mới trong SQL Server 2016:

Quy trình công việc được đề xuất để nâng cấp bộ xử lý truy vấn lên phiên bản mã mới nhất là:

  1. Nâng cấp cơ sở dữ liệu lên SQL Server 2016 mà không thay đổi cấp độ tương thích cơ sở dữ liệu (giữ ở mức trước)

  2. Cho phép lưu trữ truy vấn trên cơ sở dữ liệu. Để biết thêm thông tin về việc bật và sử dụng kho lưu trữ truy vấn, hãy xem Hiệu suất theo dõi bằng cách sử dụng Cửa hàng truy vấn.

  3. Chờ đủ thời gian để thu thập dữ liệu đại diện của khối lượng công việc.

  4. Thay đổi mức độ tương thích của cơ sở dữ liệu thành 130

  5. Sử dụng SQL Server Management Studio, đánh giá xem có hồi quy hiệu suất trên các truy vấn cụ thể sau khi thay đổi mức độ tương thích

  6. Đối với các trường hợp có hồi quy, hãy buộc kế hoạch trước trong kho lưu trữ truy vấn.

  7. Nếu có các gói truy vấn không bắt buộc hoặc nếu hiệu suất vẫn không đủ, hãy xem xét hoàn nguyên mức độ tương thích về cài đặt trước đó và sau đó tham gia Hỗ trợ khách hàng của Microsoft.

Tôi không nói rằng bạn cần hạ cấp xuống SQL Server 2012 và bắt đầu lại, nhưng kỹ thuật chung được mô tả có thể hữu ích cho bạn.

2. Tôi có nên "buộc" kế hoạch hoạt động tốt bây giờ không?

Điều đó hoàn toàn phụ thuộc vào bạn. Nếu bạn tin rằng bạn có một gói truy vấn hoạt động tốt cho tất cả các tham số đầu vào có thể, hãy thoải mái với chức năng của cửa hàng truy vấn và muốn yên tâm đi kèm với việc buộc một kế hoạch truy vấn thì hãy thực hiện. Buộc các kế hoạch truy vấn có hồi quy là một phần trong chính sách khuyến nghị nâng cấp của Microsoft lên SQL Server 2016.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.