2010-02-19 20 views
11

Tôi đang cố gắng tối ưu hóa một truy vấn SQL phức tạp và nhận được các kết quả cực kỳ khác nhau khi tôi thực hiện các thay đổi dường như không quan trọng.Câu đố hiệu suất truy vấn T-SQL: Tại sao sử dụng biến làm nên sự khác biệt?

Ví dụ, điều này mất 336 mili giây để chạy:

Declare @InstanceID int set @InstanceID=1; 
With myResults as (
    Select 
     Row = Row_Number() Over (Order by sv.LastFirst), 
     ContactID 
    From DirectoryContactsByContact(1) sv 
    Join ContainsTable(_s_Contacts, SearchText, 'john') fulltext on (fulltext.[Key]=ContactID) 
    Where IsNull(sv.InstanceID,1) = @InstanceID 
    and len(sv.LastFirst)>1 
) Select * From myResults Where Row between 1 and 20; 

Nếu tôi thay thế @InstanceID với một số mã hóa cứng, phải mất hơn 13 giây (13.890 ms) để chạy:

Declare @InstanceID int set @InstanceID=1; 
With myResults as (
    Select 
     Row = Row_Number() Over (Order by sv.LastFirst), 
     ContactID 
    From DirectoryContactsByContact(1) sv 
    Join ContainsTable(_s_Contacts, SearchText, 'john') fulltext on (fulltext.[Key]=ContactID) 
    Where IsNull(sv.InstanceID,1) = 1 
    and len(sv.LastFirst)>1 
) Select * From myResults Where Row between 1 and 20; 

Trong các trường hợp khác, tôi nhận được hiệu ứng ngược lại chính xác: Ví dụ: sử dụng biến @s thay cho chữ 'john' làm cho truy vấn chạy chậm hơn theo thứ tự độ lớn.

Ai đó có thể giúp tôi kết hợp điều này với nhau không? Khi nào một biến làm cho mọi thứ nhanh hơn, và khi nào nó làm cho mọi thứ chậm hơn?

+0

Bạn nhận ra rằng sử dụng 'TOP 20' và di chuyển ORDER BY từ ROW_NUMBER có nghĩa là bạn không cần CTE? –

+0

@OMG: chỉ khi những con số đó không bao giờ thay đổi - nếu anh ta muốn nhận hàng 800 - 820, phương pháp CTE nhanh hơn nhiều –

+0

@OMG: @Gabriel là đúng, điều này được sử dụng để phân phối kết quả phân trang, vì vậy nó có thể là 'Row giữa 20 và 40', v.v. –

Trả lời

2

Nguyên nhân có thể là IsNull(sv.InstanceID,1) = @InstanceID rất chọn lọc đối với một số giá trị @InstanceID, nhưng không chọn lọc cho những giá trị khác. Ví dụ: có thể có hàng triệu hàng với InstanceID = null, do đó, đối với @InstanceID = 1, quá trình quét có thể nhanh hơn.

Nhưng nếu bạn cung cấp giá trị @InstanceID, SQL Server biết dựa trên thống kê bảng cho dù có chọn lọc hay không.

tiên, đảm bảo thống kê của bạn luôn được cập nhật:

UPDATE STATISTICS table_or_indexed_view_name 

Sau đó, nếu vấn đề vẫn còn xảy ra, so sánh kế hoạch thực hiện truy vấn cho cả hai phương pháp. Sau đó, bạn có thể thực thi phương pháp nhanh nhất bằng cách sử dụng query hints.

+0

vị trí bật. Tôi nghi ngờ số liệu thống kê đã lỗi thời. –

+0

Điều đó có nghĩa là số liệu thống kê cũng giúp dự đoán biến được tính toán có thể là gì trong một thủ tục được lưu trữ? – dsum

0

Với giá trị được mã hóa cứng, trình tối ưu hóa biết những gì cần dựa trên khi xây dựng kế hoạch thực hiện. Khi bạn sử dụng các biến, nó cố gắng "đoán" giá trị và trong nhiều trường hợp, nó không phải là giá trị tốt nhất.

Bạn có thể giúp nó để chọn một giá trị để tối ưu hóa theo 2 cách:

  1. "Tôi biết rõ hơn", điều này sẽ buộc nó để sử dụng giá trị bạn cung cấp.

    OPTION (tối ưu hóa cho (@ InstanceID = 1)) giá trị

  2. "Xem những gì tôi làm", điều này sẽ hướng dẫn nó để sniff các giá trị bạn vượt qua và sử dụng trung bình (hoặc phổ biến nhất đối với một số kiểu dữ liệu) của những người được cung cấp theo thời gian.

    OPTION (tối ưu hóa cho UNKNOWN)

+0

'OPTION (OPTIMIZE FOR UNKNOWN)' sẽ dẫn đến chính xác hành vi "đoán" giống như sử dụng một biến. 'tùy chọn (biên dịch lại)' sẽ khiến SQL Server biên dịch lại câu lệnh có tính đến giá trị biến thực tế. –

+0

OPTION (OPTIMIZE FOR UNKNOWN) sẽ cho phép SQL căn cứ vào quá trình đoán dựa trên giá trị thực tế bạn vượt qua theo thời gian vì vậy nó không giống nhau mặc dù bạn có thể kích hoạt hành vi đó theo mặc định cho tất cả SP – root

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