Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Việc gán các tham số đầu vào thủ tục được lưu trữ cho các biến cục bộ có giúp tối ưu hóa truy vấn không?

Tôi sẽ không thử và giải thích chi tiết đầy đủ về tính năng đánh hơi tham số, nhưng tóm lại, không, nó không luôn luôn trợ giúp (và nó có thể cản trở).

Hãy tưởng tượng một bảng (T) có khóa chính và cột Ngày được lập chỉ mục (A), trong bảng có 1.000 hàng, 400 có cùng giá trị là A (giả sử hôm nay là 20130122), 600 hàng còn lại là 600 ngày tiếp theo , vì vậy chỉ có 1 bản ghi mỗi ngày.

Truy vấn này:

SELECT *
FROM T
WHERE A = '20130122';

Sẽ mang lại một kế hoạch thực hiện khác cho:

SELECT *
FROM T
WHERE A = '20130123';

Vì số liệu thống kê sẽ chỉ ra rằng 400 trong số 1.000 hàng đầu tiên sẽ được trả lại, trình tối ưu hóa sẽ nhận ra rằng quét bảng sẽ hiệu quả hơn tra cứu dấu trang, trong khi thao tác thứ hai sẽ chỉ mang lại 1 hàng, vì vậy tra cứu dấu trang sẽ rất nhiều. hiệu quả hơn.

Bây giờ, trở lại câu hỏi của bạn, nếu chúng tôi thực hiện đây là một thủ tục:

CREATE PROCEDURE dbo.GetFromT @Param DATE
AS
    SELECT *
    FROM T
    WHERE A = @Param

Sau đó chạy

EXECUTE dbo.GetFromT '20130122'; --400 rows

Kế hoạch truy vấn với quá trình quét bảng sẽ được sử dụng, nếu lần đầu tiên bạn chạy nó, bạn sử dụng '20130123' làm tham số, nó sẽ lưu trữ kế hoạch tra cứu dấu trang. Cho đến khi quy trình được biên dịch lại, kế hoạch sẽ vẫn như cũ. Làm điều gì đó như thế này:

CREATE PROCEDURE dbo.GetFromT @Param VARCHAR(5)
AS
    DECLARE @Param2 VARCHAR(5) = @Param;
    SELECT *
    FROM T
    WHERE A = @Param2

Sau đó, điều này được chạy:

EXECUTE dbo.GetFromT '20130122';

Mặc dù thủ tục được biên dịch trong một lần, nhưng nó không diễn ra đúng quy trình, do đó, kế hoạch truy vấn được tạo ở lần biên dịch đầu tiên không có ý tưởng rằng @ Param2 sẽ trở thành giống như @param, vì vậy trình tối ưu hóa (không biết có bao nhiêu hàng để kỳ vọng) sẽ giả sử 300 sẽ được trả về (30%), như vậy sẽ coi việc quét bảng hiệu quả hơn so với tra cứu dấu trang. Nếu bạn chạy cùng một quy trình với '20130123' dưới dạng một tham số, nó sẽ mang lại cùng một kế hoạch (bất kể tham số đó được gọi lần đầu tiên là gì) vì không thể sử dụng thống kê cho một giá trị chưa xác định. Vì vậy, chạy thủ tục này cho '20130122' sẽ hiệu quả hơn, nhưng đối với tất cả các giá trị khác sẽ kém hiệu quả hơn so với không có tham số cục bộ (giả sử thủ tục không có tham số cục bộ được gọi đầu tiên với bất kỳ thứ gì ngoại trừ '20130122')

Một số truy vấn để trình bày để bạn có thể xem kế hoạch thực hiện cho chính mình

Tạo lược đồ và dữ liệu mẫu

CREATE TABLE T (ID INT IDENTITY(1, 1) PRIMARY KEY, A DATE NOT NULL, B INT,C INT, D INT, E INT);

CREATE NONCLUSTERED INDEX IX_T ON T (A);

INSERT T (A, B, C, D, E)
SELECT  TOP 400 CAST('20130122' AS DATE), number, 2, 3, 4 
FROM    Master..spt_values 
WHERE   type = 'P'
UNION ALL
SELECT TOP 600 DATEADD(DAY, number, CAST('20130122' AS DATE)), number, 2, 3, 4 
FROM    Master..spt_values 
WHERE   Type = 'P';
GO
CREATE PROCEDURE dbo.GetFromT @Param DATE
AS
    SELECT *
    FROM T
    WHERE A = @Param
GO
CREATE PROCEDURE dbo.GetFromT2 @Param DATE
AS
    DECLARE @Param2 DATE = @Param;
    SELECT *
    FROM T
    WHERE A = @Param2
GO

Chạy các thủ tục (hiển thị kế hoạch thực hiện thực tế):

EXECUTE GetFromT '20130122';
EXECUTE GetFromT '20130123';
EXECUTE GetFromT2 '20130122';
EXECUTE GetFromT2 '20130123';
GO
EXECUTE SP_RECOMPILE GetFromT;
EXECUTE SP_RECOMPILE GetFromT2;
GO
EXECUTE GetFromT '20130123';
EXECUTE GetFromT '20130122';
EXECUTE GetFromT2 '20130123';
EXECUTE GetFromT2 '20130122';

Bạn sẽ thấy rằng lần đầu tiên GetFromT được biên dịch, nó sử dụng quét bảng và giữ lại điều này khi chạy với tham số '20130122', GetFromT2 cũng sử dụng quét bảng và giữ lại kế hoạch cho '20130122'.

Sau khi các thủ tục đã được thiết lập để biên dịch lại và chạy lại (lưu ý theo thứ tự khác), GetFromT sử dụng vòng lặp dấu trang và giữ lại kế hoạch cho '20130122', mặc dù trước đó đã cho rằng quét bảng là một kế hoạch phù hợp hơn. GetFromT2 không bị ảnh hưởng bởi đơn đặt hàng và có cùng kế hoạch như trước khi cải tiến.

Vì vậy, tóm lại, nó phụ thuộc vào việc phân phối dữ liệu và các chỉ mục của bạn, tần suất biên dịch lại và một chút may mắn về việc liệu một thủ tục có được lợi khi sử dụng các biến cục bộ hay không. Nó chắc chắn không luôn luôn giúp đỡ.

Hy vọng rằng tôi đã làm sáng tỏ tác dụng của việc sử dụng các tham số cục bộ, kế hoạch thực thi và khiếu nại thủ tục được lưu trữ. Nếu tôi đã thất bại hoàn toàn hoặc bỏ lỡ một điểm chính, bạn có thể tìm thấy lời giải thích chuyên sâu hơn ở đây:

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



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. sql:XÓA + CHÈN so với CẬP NHẬT + CHÈN

  2. Các khóa chính có bị khóa không?

  3. SQL INSERT INTO từ nhiều bảng

  4. Cách xóa các hàng trùng lặp hoàn toàn

  5. Tại sao (và cách) chia cột bằng cách sử dụng master..spt_values?