2013-06-10 19 views
5

tôi có một cái nhìn mà chạy nhanh (< 1s) khi xác định một giá trị trong mệnh đề where:T-SQL Chọn từ quan điểm chậm hơn nhiều với biến

SELECT * 
FROM vwPayments 
WHERE AccountId = 8155 

Execution plan for first query

... nhưng chạy chậm (~ 3s) khi giá trị đó là một biến:

DECLARE @AccountId BIGINT = 8155 

SELECT * 
FROM vwPayments 
WHERE AccountId = @AccountId 

Execution plan for second query

Tại sao kế hoạch thực hiện lại khác với truy vấn thứ hai? Tại sao nó chạy chậm hơn rất nhiều?

Trả lời

1

Tóm lại, trình tối ưu hóa truy vấn sử dụng để chọn gói tốt nhất chọn tìm khi giá trị là giá trị đã biết và có thể tận dụng thống kê và quét khi giá trị không được biết. Nó chọn quét trong lựa chọn thứ hai bởi vì kế hoạch được biên dịch trước khi giá trị của mệnh đề where được biết đến.

Mặc dù tôi hiếm khi giới thiệu phân tích truy vấn xung quanh trong trường hợp cụ thể này, bạn có thể sử dụng gợi ý forceseek hoặc gợi ý truy vấn khác để ghi đè công cụ. Tuy nhiên, hãy nhận biết rằng việc tìm cách để có được một kế hoạch tối ưu với sự trợ giúp của động cơ là một giải pháp tốt hơn MUCH.

Tôi đã làm một Google nhanh chóng và tìm thấy một decent article mà đi vào khái niệm về biến địa phương ảnh hưởng đến kế hoạch truy vấn sâu hơn.

+1

forceeek làm việc độc đáo – Domenic

+0

Chỉ cần cẩn thận với nó, bạn có thể gặp nhiều rắc rối khi cố gắng thông minh hơn công cụ truy vấn. – RThomas

0

Nó có thể là tham số đánh hơi. Hãy thử và làm như sau - Tôi cho rằng nó đang trong một thủ tục lưu sẵn?

 
DECLARE @Local_AccountId BIGINT = @AccountId 

SELECT * 
FROM vwPayments 
WHERE AccountId = @Local_AccountId 

Để biết chi tiết về thông số đánh hơi, bạn có thể xem liên kết này: http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx

Xem nếu kết quả khác nhau. Tôi đã gặp phải vấn đề này nhiều lần, đặc biệt là nếu truy vấn được gọi là rất nhiều trong các đỉnh núi và kế hoạch thực hiện được lưu trữ là một trong đó đã được tạo ra khi off-peak.

Tùy chọn khác, nhưng bạn không cần trong trường hợp của mình là thêm "WITH RECOMPILE" vào định nghĩa quy trình. Điều này sẽ làm cho thủ tục được biên dịch lại mỗi khi nó được gọi. Xem http://www.techrepublic.com/article/understanding-sql-servers-with-recompile-option/5662581

+0

nó không phải trong một thủ tục lưu trữ. – Domenic

+0

Nếu bạn tạo biến giả như tôi đã đề xuất, các kết quả có khác nhau không? Kế hoạch thực thi phải luôn luôn duy trì trong trường hợp đó và bạn sẽ có một thời gian liên tục để thực hiện truy vấn này. – Mez

0

Có phải AccountID thực sự là kiểu dữ liệu BIGINT? Một chuyển đổi có thể làm chậm nó xuống không?

+0

Đây là loại BIGINT. – Domenic

4

Trong trường hợp đầu tiên, giá trị tham số đã được biết khi biên dịch câu lệnh. Trình tối ưu hóa đã sử dụng biểu đồ thống kê để tạo ra kế hoạch tốt nhất cho giá trị thông số cụ thể đó.

Khi bạn xác định biến cục bộ, máy chủ SQL không thể sử dụng giá trị tham số để tìm 'giá trị tối ưu'. Vì giá trị tham số không xác định tại thời gian biên dịch, trình tối ưu hóa tính toán số hàng được ước tính dựa trên 'phân phối đồng đều'. Trình tối ưu hóa đã đưa ra một kế hoạch sẽ là 'đủ tốt' cho bất kỳ giá trị tham số đầu vào nào có thể.

Một bài viết thú vị khác gần như mô tả chính xác trường hợp của bạn có thể được tìm thấy here.

0

Tôi nghĩ @souplex làm một điểm rất tốt

Về cơ bản ở trường hợp đầu tiên nó chỉ là một số và dễ dàng cho hệ thống để hiểu, trong khi một trong 2 là biến có nghĩa là mỗi khi hệ thống cần phải tìm ra rất giá trị của nó và làm việc kiểm tra đối với từng tuyên bố, mà là một phương pháp khác nhau

1
DECLARE @Local_AccountId BIGINT = @AccountId 

SELECT * 
FROM vwPayments 
WHERE AccountId = @Local_AccountId 
OPTION(RECOMPILE) 

nó làm việc cho tôi

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