Thủ tục được lưu trữ chậm khi được gọi từ web, nhanh từ Management Studio


97

Tôi đã lưu trữ thủ tục hết thời gian điên cuồng mỗi khi nó được gọi từ ứng dụng web.

Tôi đã kích hoạt Sql Profiler và theo dõi các cuộc gọi hết thời gian đó và cuối cùng phát hiện ra những điều sau:

  1. Khi thực thi các câu lệnh từ bên trong MS SQL Management Studio, với các đối số tương tự (trên thực tế, tôi đã sao chép lệnh gọi thủ tục từ dấu vết hồ sơ sql và chạy nó): Nó kết thúc sau 5 ~ 6 giây trung bình.
  2. Nhưng khi được gọi từ ứng dụng web, phải mất hơn 30 giây (theo dõi) nên trang web của tôi thực sự hết thời gian chờ đợi.

Ngoài thực tế là ứng dụng web của tôi có người dùng riêng, mọi thứ đều giống nhau (cùng một cơ sở dữ liệu, kết nối, máy chủ, v.v.) Tôi cũng đã thử chạy truy vấn trực tiếp trong studio với người dùng của ứng dụng web và không mất quá 6 giây

Làm cách nào để tìm hiểu điều gì đang xảy ra?

Tôi giả định rằng nó không liên quan gì đến thực tế là chúng tôi sử dụng các lớp BLL> DAL hoặc Bộ điều hợp bảng vì dấu vết cho thấy rõ ràng sự chậm trễ trong quy trình thực tế. Đó là tất cả những gì tôi có thể nghĩ đến.

CHỈNH SỬA Tôi phát hiện ra trong liên kết này rằng ADO.NET đặt ARITHABORTthành true - điều này tốt trong hầu hết thời gian nhưng đôi khi điều này xảy ra và giải pháp được đề xuất là thêm with recompiletùy chọn vào proc được lưu trữ. Trong trường hợp của tôi, nó không hoạt động nhưng tôi nghi ngờ nó là một cái gì đó rất giống với điều này. Bất cứ ai biết ADO.NET làm gì khác hoặc nơi tôi có thể tìm thông số kỹ thuật?


1
Điều này có thể liên quan đến lượng dữ liệu đang được trả về?
Barry Kaye

@Barry: Không, vì tôi chạy cùng một quy trình (cũng được sao chép từ dấu vết - nghĩa là các thông số giống nhau) trong studio quản lý, nó chạy trong vòng 6 giây.
iamserious

@Jayantha: Vấn đề KHÔNG phải là sp chậm, mà là LỖI giữa ado.net và sql. Tôi không biết sp sẽ tạo ra bất kỳ sự khác biệt nào.
iamserious

2
SP có trả về nhiều dữ liệu, ví dụ như cột hình ảnh / văn bản / varchar (max) không? Số lượng dữ liệu cần sử dụng trên máy khách sẽ rất lớn và sẽ mất rất nhiều thời gian. SSMS cắt bỏ các tập kết quả này trong một vấn đề hiệu quả hơn.
Tim Schmelter

Câu trả lời:


79

Tôi đã gặp một vấn đề tương tự phát sinh trong quá khứ, vì vậy tôi rất mong muốn được giải quyết cho câu hỏi này. Nhận xét của Aaron Bertrand về OP dẫn đến việc Truy vấn hết thời gian khi thực thi từ web, nhưng cực nhanh khi được thực thi từ SSMS và mặc dù câu hỏi không trùng lặp, nhưng câu trả lời rất có thể áp dụng cho tình huống của bạn.

Về bản chất, có vẻ như SQL Server có thể có một kế hoạch thực thi được lưu trong bộ nhớ cache bị hỏng. Bạn đang gặp phải kế hoạch tồi tệ với máy chủ web của mình, nhưng SSMS đến với một kế hoạch khác vì có một cài đặt khác trên cờ ARITHABORT (nếu không sẽ không ảnh hưởng đến truy vấn / quy trình được lưu trữ cụ thể của bạn).

Xem ADO.NET gọi Thủ tục lưu trữ T-SQL gây ra một ngoại lệ SqlTimeoutException cho một ví dụ khác, với một lời giải thích và giải pháp đầy đủ hơn.


Đây là một số dẫn thú vị, sẽ đọc thêm về họ và say mê trở lại trong một vài .. cảm ơn.
iamserious

44
Xin chào, Xóa bộ nhớ cache DBCC DROPCLEANBUFFERSDBCC FREEPROCCACHEthực hiện thủ thuật! Tôi đoán kế hoạch thực hiện bằng cách nào đó đã bị hỏng hoặc không được cập nhật. Tôi không tin rằng đó là một bản sửa lỗi vĩnh viễn, nếu nó có thể bị hỏng một lần, nó có thể làm lại. Vì vậy, tôi vẫn đang xem xét các nguyên nhân chính đáng. Vì ứng dụng web đã hoạt động trở lại nên tôi không cần phải cảm thấy áp lực. Cảm ơn nhiều.
iamserious

2
@iamserious - bạn đã đóng đinh cảm ơn! Sau khi thay đổi quy trình đã lưu trữ của mình, tôi đã gặp sự cố hết thời gian chờ. Sau đó, tôi chạy hai lệnh DBCC mà bạn đề cập ở trên và nó đã giải quyết được vấn đề.
Induster 31/10/12

5
@Mangist: Vì đây là một vấn đề phức tạp nên không có gạch đầu dòng bạc, nhưng bạn có thể thử sử dụng OPTIMIZE FORhoặc OPTION(Recompile)truy vấn gợi ý về các truy vấn đang gây ra sự cố. Bài viết này thảo luận sâu về vấn đề. Nếu Entity Framework đang tạo truy vấn của bạn, bài đăng này dường như cung cấp một cách để thêm gợi ý truy vấn vào các truy vấn của bạn.
StriplingWarrior

8
Thay vì chạy DBCC DROPCLEANBUFFERS và DBCC FREEPROCCACHE sẽ xóa TẤT CẢ các kế hoạch thực thi mà bạn có thể loại bỏ và tạo lại thủ tục được lưu trữ vấn đề.
jnoreiga

50

Tôi cũng trải nghiệm rằng các truy vấn chạy chậm từ web và nhanh trong SSMS và cuối cùng tôi phát hiện ra rằng vấn đề là một cái gì đó được gọi là đánh giá tham số.

Cách khắc phục đối với tôi là thay đổi tất cả các tham số được sử dụng trong chương trình mầm non thành các biến cục bộ.

ví dụ. thay đổi:

ALTER PROCEDURE [dbo].[sproc] 
    @param1 int,
AS
SELECT * FROM Table WHERE ID = @param1 

đến:

ALTER PROCEDURE [dbo].[sproc] 
    @param1 int,
AS
DECLARE @param1a int
SET @param1a = @param1
SELECT * FROM Table WHERE ID = @param1a

Có vẻ lạ, nhưng nó đã khắc phục sự cố của tôi.


3
Chà, tôi cũng gặp phải vấn đề tương tự và không tin rằng điều này sẽ hiệu quả nhưng nó đã làm được.
Lạc Hồ

1
Zane, bạn có biết liệu điều này sẽ khắc phục vĩnh viễn sự cố hay nó có thể quay trở lại? Cảm ơn bạn!
Lạc Hồ

1
Kể từ khi thực hiện thay đổi này, tôi không gặp bất kỳ vấn đề nào với tốc độ của thủ tục được lưu trữ.
Zane

1
Chà, nó cũng đã khắc phục sự cố của tôi! Đây là một lỗi trong máy chủ sql. Tại sao lại buộc người viết sql phải vượt qua vòng lặp ngớ ngẩn này khi MSSQL có thể chuyển đổi nội bộ thành cục bộ dưới mui xe, để tăng hiệu suất LỚN?
HerrimanCoder

3
Có thể nào việc thay đổi proc khiến một kế hoạch thực thi mới được tạo ra, vì vậy giải pháp không thực sự là sao chép biến đầu vào thành biến cục bộ mà chỉ buộc tạo ra một kế hoạch thực thi mới (như đã giải thích trong giải pháp được chấp nhận)?
Garland Pope

10

Không phải để spam, nhưng là một giải pháp hy vọng hữu ích cho những người khác, hệ thống của chúng tôi đã thấy thời gian chờ ở mức độ cao.

Tôi đã thử đặt thủ tục đã lưu trữ được biên dịch lại bằng cách sử dụng sp_recompilevà điều này đã giải quyết được sự cố cho một SP.

Cuối cùng, có một số lượng lớn hơn SP đã hết thời gian, nhiều SP chưa bao giờ làm như vậy trước đây, bằng cách sử dụng DBCC DROPCLEANBUFFERSDBBC FREEPROCCACHEtỷ lệ sự cố hết thời gian đã giảm đáng kể - vẫn có những lần xuất hiện riêng lẻ, một số nơi tôi nghi ngờ việc tái tạo kế hoạch đang được thực hiện một thời gian và một số nơi SP thực sự kém hiệu quả và cần được đánh giá lại.


1
Cảm ơn vì điều đó. Đánh dấu quy trình biên dịch lại bằng lệnh sp_recompile đã làm việc với tôi khi DBCC DROPCLEANBUFFERSDBCC FREEPROCCACHEkhông có gì khác biệt.
Steve

4

Có thể là một số lệnh gọi DB khác được thực hiện trước khi ứng dụng web gọi SP đang giữ một giao dịch mở không? Đó có thể là một lý do để SP này đợi khi được ứng dụng web gọi. Tôi nói cô lập cuộc gọi trong ứng dụng web (đặt nó trên một trang mới) để đảm bảo rằng một số hành động trước đó trong ứng dụng web đang gây ra sự cố này.


1
Xin chào @Tundey, tôi đã cách ly cuộc gọi và nó vẫn mất khoảng 30 giây và hết thời gian. vì vậy nó phải là một cái gì đó giữa giao tiếp, tôi đoán?
iamserious

1

Đơn giản chỉ cần biên dịch lại thủ tục được lưu trữ (hàm bảng trong trường hợp của tôi) phù hợp với tôi


1

như @Zane nói có thể là do đánh hơi thông số. Tôi đã gặp phải hành vi tương tự và tôi đã xem xét kế hoạch thực thi của thủ tục và tất cả các câu lệnh của sp trong một hàng (đã sao chép tất cả các câu lệnh tạo thành thủ tục, khai báo các tham số dưới dạng biến và gán các giá trị giống nhau cho biến như các tham số có). Tuy nhiên, kế hoạch thực hiện trông hoàn toàn khác. Quá trình thực hiện sp mất 3-4 giây và các câu lệnh liên tiếp có cùng giá trị được trả về ngay lập tức.

kế hoạch thực hiện

Sau một số googling, tôi đã tìm thấy một bài đọc thú vị về hành vi đó: Chậm trong ứng dụng, Nhanh trong SSMS?

Khi biên dịch thủ tục, SQL Server không biết rằng giá trị của @fromdate thay đổi, nhưng biên dịch thủ tục theo giả định rằng @fromdate có giá trị NULL. Vì tất cả các so sánh với NULL đều mang lại lợi nhuận UNKNOWN, truy vấn không thể trả về bất kỳ hàng nào, nếu @fromdate vẫn có giá trị này tại thời điểm chạy. Nếu SQL Server nhận giá trị đầu vào là chân lý cuối cùng, nó có thể xây dựng một kế hoạch chỉ có Quét liên tục hoàn toàn không truy cập vào bảng (chạy truy vấn SELECT * FROM Order WHERE OrderDate> NULL để xem ví dụ về điều này) . Nhưng SQL Server phải tạo một kế hoạch trả về kết quả chính xác cho dù @fromdate có giá trị nào tại thời điểm chạy. Mặt khác, không có nghĩa vụ phải xây dựng một kế hoạch tốt nhất cho tất cả các giá trị. Do đó, vì giả định là không có hàng nào được trả lại, nên SQL Server giải quyết cho Tìm kiếm chỉ mục.

Vấn đề là tôi có các tham số có thể được để trống và nếu chúng được chuyển dưới dạng null thì sẽ được khởi tạo với giá trị mặc định.

create procedure dbo.procedure
    @dateTo datetime = null
begin
    if (@dateTo is null)
    begin
        select @dateTo  = GETUTCDATE()
    end

    select foo
    from dbo.table
    where createdDate < @dateTo
end

Sau khi tôi thay đổi nó thành

create procedure dbo.procedure
    @dateTo datetime = null
begin
    declare @to datetime = coalesce(@dateTo, getutcdate())

    select foo
    from dbo.table
    where createdDate < @to
end 

nó lại hoạt động như một sự quyến rũ.

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.