2013-04-06 27 views
5

Chúng tôi có nhiều "thủ tục lưu trữ tìm kiếm" lấy nhiều tham số nullable để tìm kiếm các hàng dữ liệu trong các bảng khác nhau. Chúng thường được xây dựng như thế này:T-SQL - Không sử dụng kế hoạch tối ưu - Mệnh đề WHERE nên được cắt ngắn

SELECT  * 
FROM  Table1 T1 
INNER JOIN Table2 T2 
    ON  T2.something = T1.something 
WHERE  (@parameter1 IS NULL OR T1.Column1 = @parameter1) 
     AND (@parameter2 IS NULL OR T2.Column2 = @parameter2) 
     AND (@parameter3 IS NULL OR T1.Column3 LIKE '%' + @parameter3 + '%') 
     AND (@parameter4 IS NULL OR T2.Column4 LIKE '%' + @parameter4 + '%')  
     AND (@parameter5 IS NULL OR T1.Column5 = @parameter5) 

Điều này có thể tiếp tục cho đến 30-40 thông số và những gì chúng tôi nhận thấy ngay cả khi chỉ có tham số1, kế hoạch thực hiện quét qua chỉ mục của bảng có thể làm chậm truy vấn đáng kể (vài giây). Các thử nghiệm cho chúng ta thấy rằng chỉ giữ dòng đầu tiên từ câu lệnh WHERE làm cho truy vấn ngay lập tức.

  1. Tôi đã đọc shortcuiting là không thể, nhưng có cách nào hay cách để xây dựng các truy vấn có thể hiệu quả hơn? Chúng tôi hiện đang giải quyết vấn đề này bằng cách có các phiên bản khác nhau của cùng một SELECT/FROM/JOINS nhưng với các tham số khác nhau trong mệnh đề WHERE và tùy thuộc vào thông số nào được thông qua, chúng tôi chọn câu lệnh chọn thích hợp để thực hiện. Điều này là dài, lộn xộn và khó duy trì.

+3

Bạn đã cân nhắc sử dụng [SQL động] (http://www.sommarskog.se/dynamic_sql.html) chưa? Ngay cả với [SQL Injection] (http://en.wikipedia.org/wiki/SQL_injection) báo trước nó có thể phù hợp hơn với nhu cầu của bạn. – Oded

+0

Xây dựng sql động và sql tiêm tham số không phải là một vấn đề – StrayCatDBA

+0

Tôi sẽ xem lại tại sql động, nhưng có vẻ như chỉ cần quay trở lại cách chúng ta sử dụng để làm việc và xây dựng các chuỗi mã SQL phức tạp bên trong ứng dụng một loạt các điều kiện làm cho nó gần như không thể hiểu được truy vấn trong nháy mắt. Ngoài ra có cách nào để giữ nổi bật/công cụ cú pháp trong SQL studio quản lý cho các truy vấn đó không? – FrancoisCN

Trả lời

4

Kế hoạch truy vấn trong SQL Server được biên dịch và lưu trữ để sử dụng lại. Ngay cả khi SQL Server thấy rằng các tham số của bạn là null nó phải đưa ra một kế hoạch truy vấn sẽ làm việc cho các trường hợp chúng là not null.

Gợi ý truy vấn option (recompile) được giới thiệu trong SQL Server 2005 nhưng không phải cho đến khi SQL Server 2008 thực sự có ảnh hưởng đến loại truy vấn bạn có ở đây.

Khi truy vấn được biên dịch lại mỗi lần nó sẽ không được lưu trữ trong bộ nhớ cache kế hoạch truy vấn để SQL Server được tự do tối ưu hóa các kiểm tra đối với các tham số là null.

Đọc thêm về nó ở đây Dynamic Search Conditions in T-SQL

Một số mẫu mã bạn có thể thử nghiệm trên để thấy sự khác biệt trong kế hoạch truy vấn. Cuộc gọi đầu tiên tới SP sẽ thực hiện tìm kiếm chỉ mục và lần thứ hai sẽ thực hiện quét chỉ mục nhóm.

create table T 
(
    ID int identity primary key, 
    Col1 int, 
    Col2 int 
); 

go 

create index IX_T on T(Col1); 

go 

create procedure GetT 
    @Col1 int, 
    @Col2 int 
as 

select ID 
from T 
where (Col1 = @Col1 or @Col1 is null) and 
     (Col2 = @Col2 or @Col2 is null) 
option (recompile); 

go 

exec GetT 1, null 
exec GetT 1, 1 
+1

Tôi đã sử dụng phương pháp này để thành công lớn. Vấn đề duy nhất tôi gặp phải là khi số lượng biên dịch trở thành vấn đề. Sau đó, sql tham số động là lựa chọn duy nhất thực sự. – StrayCatDBA

+0

Ý của bạn là gì khi số lượng biên dịch trở thành một vấn đề? – FrancoisCN

+0

@FrancoisCN Biên dịch truy vấn lấy tài nguyên (CPU) trên máy chủ và sử dụng 'tùy chọn (biên dịch lại)' nghĩa là truy vấn sẽ được biên dịch cho mỗi lần thực thi. Vì vậy, sử dụng nó có thể đặt một căng thẳng trên máy chủ của bạn. Tác động lớn đến mức nào phụ thuộc vào độ phức tạp của truy vấn và tần suất truy vấn được thực thi. –

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