SQL Server - Nếu logic trong thủ tục được lưu trữ và bộ đệm kế hoạch


15

Tiêu chuẩn SQL Server 2012 và 2016:

Nếu tôi đặt if-elselogic trong một thủ tục được lưu trữ để thực thi một trong hai nhánh mã, tùy thuộc vào giá trị của một tham số, động cơ có lưu trữ phiên bản mới nhất không?

Và nếu trong lần thực hiện sau, giá trị của tham số thay đổi, nó sẽ biên dịch lại và lưu lại bộ đệm thủ tục đã lưu , vì một nhánh mã khác phải được thực thi? (Truy vấn này khá tốn kém để biên dịch.)

Câu trả lời:


27

Tiêu chuẩn SQL Server 2012 và 2016: Nếu tôi đặt logic if-other trong một thủ tục được lưu trữ để thực thi một trong hai nhánh mã, tùy thuộc vào giá trị của một tham số, động cơ có lưu trữ phiên bản mới nhất không?

Không, nó lưu trữ tất cả các phiên bản. Hay đúng hơn, nó lưu trữ một phiên bản với tất cả các đường dẫn được khám phá, được biên dịch với các biến được truyền.

Đây là bản demo nhanh, sử dụng cơ sở dữ liệu Stack Overflow.

Tạo một chỉ mục:

CREATE INDEX ix_yourmom ON dbo.Users (Reputation) INCLUDE (Id, DisplayName);
GO 

Tạo một thủ tục được lưu trữ với một gợi ý chỉ mục trỏ đến một chỉ mục không tồn tại, trong mã phân nhánh.

CREATE OR ALTER PROCEDURE dbo.YourMom (@Reputation INT)
AS 
BEGIN

    IF @Reputation = 1
    BEGIN
        SELECT u.Id, u.DisplayName, u.Reputation
        FROM dbo.Users AS u WITH (INDEX = PK_Users_Id)
        WHERE u.Reputation = @Reputation;
    END;

    IF @Reputation > 1
    BEGIN
        SELECT u.Id, u.DisplayName, u.Reputation
        FROM dbo.Users AS u WITH (INDEX = ix_yourdad)
        WHERE u.Reputation = @Reputation;

    END;

END;

Nếu tôi thực thi lệnh lưu trữ đó đang tìm kiếm Danh tiếng = 1, tôi sẽ gặp lỗi.

EXEC dbo.YourMom @Reputation = 1;

Msg 308, Cấp 16, Trạng thái 1, Quy trình YourMom, Dòng 14 [Dòng bắt đầu hàng loạt 32] Chỉ mục 'ix_yourdad' trên bảng 'dbo.Users' (được chỉ định trong mệnh đề TỪ) không tồn tại.

Nếu chúng tôi sửa tên chỉ mục và chạy lại truy vấn, kế hoạch lưu trữ sẽ giống như sau:

Quả hạch

Bên trong, XML sẽ có hai tham chiếu đến @Reputationbiến.

<ColumnReference Column="@Reputation" ParameterDataType="int" ParameterCompiledValue="(1)" />

Một thử nghiệm đơn giản hơn một chút sẽ chỉ là lấy một kế hoạch ước tính cho các Proc được lưu trữ. Bạn có thể thấy trình tối ưu hóa khám phá cả hai đường dẫn:

Quả hạch

Và nếu trong lần thực hiện sau, giá trị của tham số thay đổi, nó sẽ biên dịch lại và lưu lại bộ đệm thủ tục đã lưu, bởi vì một nhánh khác của mã phải được thực thi? (Truy vấn này khá tốn kém để biên dịch.) Cảm ơn bạn.

Không, nó sẽ giữ lại giá trị thời gian chạy của quá trình biên dịch đầu tiên.

Nếu chúng ta thực hiện lại với một khác @Reputation:

EXEC dbo.YourMom @Reputation = 2;

Từ kế hoạch thực tế :

<ColumnReference Column="@Reputation" ParameterDataType="int" ParameterCompiledValue="(1)" ParameterRuntimeValue="(2)" />

Chúng tôi vẫn có giá trị biên dịch là 1, nhưng bây giờ giá trị thời gian là 2.

Trong bộ đệm kế hoạch, bạn có thể kiểm tra bằng một công cụ miễn phí như công cụ của công ty tôi phát triển, sp_BlitzCache :

Quả hạch

Thủ tục được lưu trữ đã được gọi hai lần và mỗi câu lệnh trong nó đã được gọi một lần.

Vậy chúng ta có gì? Một kế hoạch lưu trữ cho cả hai truy vấn trong thủ tục được lưu trữ.

Nếu bạn muốn loại logic phân nhánh này, bạn phải gọi các thủ tục được lưu trữ phụ:

CREATE OR ALTER PROCEDURE dbo.YourMom (@Reputation INT)
AS 
BEGIN

    IF @Reputation = 1
    BEGIN

        EXEC dbo.Reputation1Query;

    END;

    IF @Reputation > 1
    BEGIN

        EXEC dbo.ReputationGreaterThan1Query;

    END;

END;

Hoặc SQL động:

DECLARE @sql NVARCHAR(MAX) = N''

SET @sql +=
N'
SELECT u.Id, u.DisplayName, u.Reputation
        FROM dbo.Users AS u '
IF @Reputation = 1
BEGIN
    SET @sql += N' (INDEX = PK_Users_Id)
        WHERE u.Reputation = @Reputation;'
END;


IF @Reputation > 1 
BEGIN

SET @sql += ' WITH (INDEX = ix_yourmom)
        WHERE u.Reputation = @Reputation;'

END;


EXEC sys.sp_executesql @sql;

Hi vọng điêu nay co ich!

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.