2010-10-22 35 views
31

Tôi đang thực hiện một số thử nghiệm bằng cách sử dụng lược tả SQL 2005.Truy vấn chạy nhanh, nhưng chạy chậm trong thủ tục được lưu trữ

Tôi có một thủ tục được lưu trữ chỉ cần chạy một truy vấn SQL.

Khi tôi chạy quy trình được lưu trữ, phải mất một thời gian dài và thực hiện 800.000 lần đọc đĩa.

Khi tôi chạy cùng một truy vấn riêng biệt với quy trình được lưu trữ, nó có 14.000 lần đọc đĩa.

Tôi thấy rằng nếu tôi chạy cùng một truy vấn với OPTION (biên dịch lại), phải mất 800.000 lần đọc đĩa.

Từ điều này, tôi làm cho giả định (có thể sai lầm) rằng thủ tục được lưu trữ được biên dịch lại mỗi lần và điều đó gây ra sự cố.

Có ai có thể làm sáng tỏ điều này không?

Tôi đã đặt ARITHABORT ON. (Điều này giải quyết một vấn đề tương tự trên stackoverflow, nhưng không giải quyết mỏ)

Dưới đây là toàn bộ thủ tục lưu trữ:

CREATE PROCEDURE [dbo].[GET_IF_SETTLEMENT_ADJUSTMENT_REQUIRED] 
@Contract_ID int, 
@dt_From smalldatetime, 
@dt_To smalldatetime, 
@Last_Run_Date datetime 
AS 
BEGIN 
DECLARE @rv int 


SELECT @rv = (CASE WHEN EXISTS 
(
    select * from 
    view_contract_version_last_volume_update 
    inner join contract_version 
    on contract_version.contract_version_id = view_contract_version_last_volume_update.contract_version_id 
    where [email protected]_ID 
    and volume_date >= @dt_From 
    and volume_date < @dt_To 
    and last_write_date > @Last_Run_Date 
) 
THEN 1 else 0 end) 

-- Note that we are RETURNING a value rather than SELECTING it. 
-- This means we can invoke this function from other stored procedures 
return @rv 
END 

Dưới đây là một kịch bản tôi chạy đó chứng tỏ vấn đề:

DECLARE 
@Contract_ID INT, 
@dt_From smalldatetime, 
@dt_To smalldatetime, 
@Last_Run_Date datetime, 
    @rv int 


SET @Contract_ID=38 
SET @dt_From='2010-09-01' 
SET @dt_To='2010-10-01' 
SET @Last_Run_Date='2010-10-08 10:59:59:070' 


-- This takes over fifteen seconds 
exec GET_IF_SETTLEMENT_ADJUSTMENT_REQUIRED @[email protected]_ID,@[email protected]_From,@[email protected]_To,@[email protected]_Run_Date 

-- This takes less than one second! 
SELECT @rv = (CASE WHEN EXISTS 
(
select * from 
view_contract_version_last_volume_update 
inner join contract_version 
on contract_version.contract_version_id = view_contract_version_last_volume_update.contract_version_id 
where [email protected]_ID 
and volume_date >= @dt_From 
and volume_date < @dt_To 
and last_write_date > @Last_Run_Date 
) 
THEN 1 else 0 end) 


-- With recompile option. Takes 15 seconds again! 
SELECT @rv = (CASE WHEN EXISTS 
(
select * from 
view_contract_version_last_volume_update 
inner join contract_version 
on contract_version.contract_version_id = view_contract_version_last_volume_update.contract_version_id 
where [email protected]_ID 
and volume_date >= @dt_From 
and volume_date < @dt_To 
and last_write_date > @Last_Run_Date 
) 
THEN 1 else 0 end) OPTION(recompile) 
+0

Sự khác nhau giữa hai "Kế hoạch thực hiện truy vấn thực tế" là gì? – Andomar

Trả lời

61

OK, chúng tôi đã có các vấn đề tương tự như thế này trước đây.

Cách chúng tôi cố định này, là bằng cách làm cho các thông số địa phương bên trong SP, như vậy mà

DECLARE @LOCAL_Contract_ID int, 
     @LOCAL_dt_From smalldatetime, 
     @LOCAL_dt_To smalldatetime, 
     @LOCAL_Last_Run_Date datetime 

SELECT @LOCAL_Contract_ID = @Contract_ID, 
     @LOCAL_dt_From = @dt_From, 
     @LOCAL_dt_To = @dt_To, 
     @LOCAL_Last_Run_Date = @Last_Run_Date 

Chúng tôi sau đó sử dụng các thông số địa phương bên trong SP chứ không phải là thông số được thông qua năm.

Điều này thường cố định vấn đề cho chúng tôi.

Chúng tôi tin rằng đây là do tham số sniffing, nhưng không có bất kỳ giấy tờ chứng minh, xin lỗi ... X-)

EDIT:

Có một cái nhìn tại Different Approaches to Correct SQL Server Parameter Sniffing cho một số ví dụ sâu sắc, giải thích và sửa lỗi.

+3

Và bây giờ các thủ tục được lưu trữ đi quá nhanh nó có 0 thời gian trong hồ sơ. Không thể tin được. Tôi có nên lo lắng về Lập trình Cult hàng hóa không? Ngay bây giờ tôi rất vui mừng vì nó đã được sửa. :-) –

+0

Điều này cũng khắc phục được sự cố của tôi. Không thực sự chắc chắn làm thế nào điều này làm cho bất kỳ kể từ. Truy vấn chạy trong 7 giây và thủ tục lưu trữ mất hơn 7 phút. Sử dụng Biến cục bộ mà nó chạy trong 6 giây. Cảm ơn! – buzzzzjay

+0

Tôi ghi 2 ngày để tăng hiệu suất của quy trình lưu trữ, mất 1 phút & 20 giây để thực hiện nhưng khi tôi thay đổi hoàn tất chỉ trong 3 giây. Cảm ơn! :) – Hitusam

4

Tôi đoán đây là do parametersniffing.

+0

+1 - đó là dành cho chúng tôi, chúng tôi đã theo dõi câu trả lời được đưa ra bởi [Adam Marshall] (http://stackoverflow.com/users/134653/adam -marshall) trong [SO: SQL Server: Truy vấn nhanh, nhưng chậm từ thủ tục] (http://stackoverflow.com/questions/440944/sql-server-query-fast-but-slow-from-procedure) và nó giảm thời gian chạy sp của chúng tôi từ ** 20 MINUTES ** đến ** 4 GIÂY ** –

3

Vấn đề tại sao một đợt mất mãi mãi để chạy bên trong một thủ tục lưu trữ SQL chưa chạy ngay lập tức trong SSMS đã làm với tham số SQL sniffing, đặc biệt là với các thông số datetime.

Có một số bài viết tuyệt vời về tham số đánh hơi ra khỏi đó.

Đây là một trong số họ (tôi không viết nó, chỉ cần chuyển nó lên).

http://www.sommarskog.se/query-plan-mysteries.html

3

Như những người khác đã đề cập, đây có thể là một 'thông số đánh hơi' vấn đề.Hãy thử bao gồm dòng:

OPTION (RECOMPILE) 

ở cuối truy vấn SQL của bạn.

Có một bài viết ở đây giải thích những gì tham số sniffing là: http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx

+0

+1 - đó là dành cho chúng tôi, chúng tôi đã theo dõi câu trả lời được đưa ra bởi [Adam Marshall] (http://stackoverflow.com/users/134653/adam -marshall) trong [SO: SQL Server: Truy vấn nhanh, nhưng chậm từ thủ tục] (http://stackoverflow.com/questions/440944/sql-server-query-fast-but-slow-from-procedure) và nó giảm thời gian chạy sp của chúng tôi từ ** 20 MINUTES ** đến ** 4 SECONDS ** –

1

tôi cũng có cùng một vấn đề ngày hôm nay. Tôi đã bỏ và tái tạo SP và nó hoạt động. Đây là một cái gì đó với bộ nhớ cache SP và khi bỏ SP, kế hoạch lưu trữ đã bị xóa. Bạn có thể thử tương tự hoặc sử dụng 'DBCC FREEPROCCACHE' để xóa bộ nhớ cache.

Các vấn đề liên quan