Kế hoạch thực hiện đột ngột chậm cho Proc lưu trữ


15

Tôi đang cố gắng hiểu vấn đề chúng tôi gặp phải với SQL Server 2000. Chúng tôi là một trang web giao dịch vừa phải và chúng tôi có một kho lưu trữ được gọi là sp_GetCurrentTransactionschấp nhận ID khách hàng và hai ngày.

Bây giờ tùy thuộc vào ngày và khách hàng, truy vấn này có thể trả về mọi thứ từ 0 đến 1000 hàng.

Vấn đề: những gì chúng tôi đã trải qua là đột nhiên chúng tôi sẽ nhận được một số lỗi (thường Execution Timeout Expiredhoặc tương tự) cho một khách hàng cụ thể trong khi họ thử thực thi lệnh lưu trữ đó. Vì vậy, chúng tôi kiểm tra truy vấn, chạy nó trong SSMS và thấy rằng phải mất 30 giây. Vì vậy, chúng tôi biên dịch lại các Proc được lưu trữ và -bang- nó chạy trong 300ms.

Tôi đã nói chuyện với DBA của chúng tôi về điều này. Anh ấy đã nói với tôi rằng cơ sở dữ liệu đã tạo ra một kế hoạch truy vấn khi chúng tôi tạo ra các lưu trữ được lưu trữ. Ông nói rằng đó là một kế hoạch tốt cho bộ tham số đó, nhưng nếu bạn ném một bộ thông số nhất định vào nó, thì kế hoạch đó sẽ không phải là kế hoạch tốt nhất cho dữ liệu đó, và vì vậy bạn sẽ thấy nó chạy chậm.

Các tùy chọn được trình bày cho tôi là việc di chuyển vấn đề truy vấn từ một Proc được lưu trữ và quay lại SQL động có kế hoạch thực hiện được tạo trong mỗi lần chạy.

Cảm giác này giống như một bước lùi lại với tôi và tôi cảm thấy như phải có một cách xung quanh điều này. Có cách nào khác để giải quyết vấn đề này không?

Bất kỳ và tất cả các câu trả lời được đánh giá cao.


Có một tuyên bố if / other trong Proc không? Tôi đã thấy điều này xảy ra khi kế hoạch được lưu trữ trong câu lệnh if và sau đó cố gắng thực thi theo khối khác bằng cách sử dụng kế hoạch sai. Có phải những lỗi này tương ứng với một sự thay đổi trong Proc?
Jeremy Gray

@Jeremy: Không có thay đổi đối với Proc và không có câu lệnh / if nào khác.
Ciaran Archer

Câu trả lời:


14

Vấn đề này được gọi là đánh hơi tham số.

Các phiên bản sau của SQL Server cung cấp cho bạn nhiều tùy chọn hơn trong việc xử lý nó như OPTION (RECOMPILE)hoặc OPTIMIZE FORgợi ý.

Bạn có thể thử khai báo các biến trong thủ tục được lưu trữ, gán các giá trị tham số cho các biến và sử dụng các biến thay cho các tham số vì nó có vẻ như hầu hết thời gian bạn đang có một kế hoạch hợp lý thỏa đáng.

Thông thường các kế hoạch tồi tệ nhất là những kế hoạch được biên dịch cho các tham số có độ chọn lọc rất cao nhưng được chạy với các tham số có độ chọn lọc thấp.

Giả sử kế hoạch được tạo ra mạnh mẽ hơn với cách tiếp cận này và thỏa đáng cho tất cả các giá trị tham số thì ưu điểm của phương pháp này so với đề xuất của JNK là nó không phát sinh chi phí biên dịch cho mỗi cuộc gọi.

Nhược điểm là đối với một số lần thực thi, thời gian chạy có thể lớn hơn so với kế hoạch được thiết kế riêng cho các giá trị tham số đó vì vậy nó là sự đánh đổi thời gian biên dịch so với thời gian thực hiện.


3
Hoặc "liên kết nhìn trộm" theo thuật ngữ của Oracle
Gaius

Cảm ơn @Gaius, thật tốt khi biết thuật ngữ cho nhiều hơn một RDBMS;)
Andrei Rînea

6

Thay vì sử dụng SQL động, bạn luôn có thể thay đổi các lệnh gọi của bạn thành:

EXEC Database.dbo.usp_Myprocedure 'Parameter' WITH RECOMPILE

Các WITH RECOMPILElực lượng (bạn đoán nó!) Một biên dịch lại kế hoạch thực hiện bất cứ khi nào nó được chạy.

Bạn cũng có thể bao gồm WITH RECOMPILEtrong định nghĩa của Proc được lưu trữ:

CREATE PROCEDURE usp.MyProcedure (Parameters)
WITH RECOMPILE
AS
...

2

Bạn cũng có thể cố gắng quyết định cơ sở dữ liệu sẽ sử dụng kế hoạch nào, mặc dù bạn sẽ chiến đấu với trình tối ưu hóa một chút, vì vậy nó dễ vỡ hơn bạn mong đợi.

Kỹ thuật này là - chia thủ tục được lưu trữ thành 2, một nghĩa là cho một bộ tham số, một cho tham số khác. Thêm các mệnh đề cho mỗi mệnh đề mà giữa chúng, chúng bao gồm tất cả các trường hợp có thể. Nhìn vào các kế hoạch truy vấn - một nên được tối ưu hóa cho một bộ tham số, bộ kia cho bộ kia. Bạn có thể phải sửa lại truy vấn để thực hiện điều này hoặc điều này có thể không đạt được cho truy vấn của bạn, trong trường hợp phương pháp này không hiệu quả.

Bây giờ làm cho thủ tục được lưu trữ ban đầu của bạn kiểm tra các giá trị tham số và gửi đến một trong hai thủ tục được lưu trữ từ đoạn trước.

Điều này có thể hoạt động, nhưng đó là một cách hack để buộc trình tối ưu hóa hoạt động hiệu quả hơn cho truy vấn của bạn. Giống như tất cả các bản hack như vậy, trong các phiên bản tương lai của cơ sở dữ liệu, nó có thể không cần thiết hoặc thậm chí làm cho mọi thứ tồi tệ hơn. Vì vậy, ngay cả khi nó hoạt động, bạn phải quyết định xem nó có xứng đáng hay không.



0

Hmmm ... nếu chúng ta chỉ tập trung vào một thủ tục được lưu trữ này, tôi sẽ ngạc nhiên rằng việc sử dụng kế hoạch thực thi được lưu trong bộ nhớ cache sẽ gây ra sự cố mà bạn đang gặp phải. Tôi sẽ yêu cầu xem kế hoạch thực hiện của thủ tục được lưu trữ bằng cách sử dụng một bộ tham số cho khách hàng và hai ngày. Tôi tự hỏi nếu một chỉ mục cụ thể hơn sẽ hữu ích -> chẳng hạn như trên customerId, và chỉ hai ngày?


2
Tại sao bất ngờ? đánh hơi thông số là một vấn đề khá phổ biến với các triệu chứng này và có vẻ như DBA đã xác định đó là vấn đề.
Martin Smith

@MartinSmith - Tôi hơi ngạc nhiên một chút rằng DBA biết về việc đánh hơi thông số không biết về gợi ý biên dịch lại mặc dù ...
JNK

@JNK - Đó là sự thật. Không chắc tại sao họ sẽ không đề cập đến điều đó.
Martin Smith

0

Hiệu suất đột ngột giảm âm thanh giống như một kế hoạch truy vấn không hiệu quả được tạo ra, có thể là kết quả của việc thiếu số liệu thống kê. Chạy trình cấu hình SQL Server với các danh mục sự kiện "Lỗi và cảnh báo" được đặt và xem có cảnh báo nào về các số liệu thống kê bị thiếu hay không.

Bạn cũng có thể đang thiếu một chỉ mục hoặc bạn có thể cần phải phân mảnh các chỉ mục vì chúng có thể quá phân mảnh để SQL Server sử dụng, dẫn đến suy nghĩ rằng Quét bảng sẽ tạo ra ít I / O hơn.

@JNK nêu lên một điểm tuyệt vời về các procs được lưu trữ - chúng được biên dịch trả trước và kế hoạch truy vấn sẽ được lưu trữ cùng với thủ tục được lưu trữ.

Tôi không nhất thiết phải đồng ý với việc sử dụng VỚI RECOMPILE khi bạn mất lợi ích của gói truy vấn đang được lưu trữ và sử dụng lại. Có một số trường hợp khi điều này là cần thiết - tức là nếu số liệu thống kê phân phối của bạn trong các bảng bên dưới khác nhau rất nhiều giữa các cuộc gọi, nhưng nhìn chung, một khi dữ liệu trong các bảng đã hoàn tất, việc phân phối dữ liệu trong các bảng sẽ thay đổi tối thiểu.

Vì vậy, để tóm tắt:

  1. Kiểm tra số liệu thống kê còn thiếu
  2. Kiểm tra phân mảnh chỉ số
  3. Tạo và sử dụng một Proc được lưu trữ
  4. Vui lòng đổi tên Proc - sp_ là không gian tên tiền tố được dành riêng cho các hệ thống SQL Server nội bộ - dẫn đến SQL Server luôn tìm kiếm trong cơ sở dữ liệu chính cho các quy trình được lưu trữ đó trước tiên. Đổi tên Proc usp_ thay vì sp_ sẽ dẫn đến tăng hiệu suất, nhưng tôi nghi ngờ vấn đề của bạn trong trường hợp này.
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.