Có cách nào để thực hiện kiểm tra null trên một biến trong mệnh đề WHERE chỉ xảy ra một lần không?


11

Tôi có một truy vấn trên một bảng lớn trông như thế này:

declare @myIdParam int = 1

select * 
from myTable
where (@myIdParam is null or myTable.Id = @myIdParam)

Có một số điều kiện tương tự như thế này trong mệnh đề where và cũng có rất nhiều phép nối, nhưng đây là một bản tóm tắt.

Thực tế, nếu @myIdParam là null, chúng tôi không muốn hạn chế kết quả bằng tham số này.

Tôi không phải là DB pro, nhưng từ các thử nghiệm của tôi, có vẻ như kiểm tra NULL này được thực hiện cho mọi bản ghi và không được tối ưu hóa theo bất kỳ cách nào.

Nếu tôi loại bỏ kiểm tra null và giả sử tham số không phải là null, truy vấn sẽ trả về ngay lập tức. Nếu không, phải mất đến mười giây.

Có cách nào để tối ưu hóa điều này để việc kiểm tra chỉ được thực hiện một lần khi chạy không?


1
Nhìn vào câu trả lời này: stackoverflow.com/questions/3415582/ Cách sử dụngOPTION(RECOMPILE)
vercelli

@vercelli cái này không lừa được. Xem xét câu hỏi này thực sự là về các tham số tùy chọn, tôi muốn nói rằng đó là một bản sao của tham số bạn đã liên kết.
Mystagogue

Có thể, nhưng đó là một bài viết từ 6 năm trước. Có thể với SqlServer 2014 hoặc 2016 có một cách tiếp cận mới. (Tôi đã thử nghiệm nó vào năm 2014 mà không cần biên dịch lại và mất mãi mãi)
vercelli

Vì truy vấn thực tế của bạn có nhiều tham số tùy chọn, SQL động sẽ cung cấp hiệu suất tốt nhất. Xem sommarskog.se/dyn-search.html để biết bài viết kỹ lưỡng về chủ đề này.
Dan Guzman

@DanGuzman sử dụng VỚI RECOMPILE như được nêu trong câu hỏi vercelli được liên kết đã cắt giảm thời gian truy vấn từ chỉ dưới một phút để thực tế ngay lập tức với các tiêu chí có tính chọn lọc cao. Tôi coi đây là lựa chọn tốt nhất để cân bằng giữa hiệu suất và khả năng đọc.
Mystagogue

Câu trả lời:


8

Một cách là sử dụng SQL động, sử dụng kiểm tra null để tùy ý thêm phần đó của mệnh đề where.

declare @myIdParam int = 1
declare @vc_dynamicsql varchar(max)

set @vc_dynamicsql = 'select * from myTable where 1=1'

if @myIdParam is not null
    set @vc_dynamicsql = @vc_dynamicsql + ' and  myTable.Id = @myIdParam'

EXECUTE sp_executesql @vc_dynamicsql

2
Tôi thực sự không muốn làm điều này, nhưng nó là một giải pháp. Hy vọng của tôi là ai đó đi cùng với một người tốt hơn nhiều.
Mystagogue

1
Đây là cách tốt nhất để xử lý lớp truy vấn tìm kiếm này. Các câu trả lời stackoverflow gọi bằng @vercelli chứa tài liệu tham khảo tuyệt vời cho làm thế nào để làm điều này.
Max Vernon

Đây là phương pháp tốt nhất nhưng tôi đã nhận thấy rằng tham số @params sp_ExecuteSQLbị thiếu và @vc_dynamicsqltham số cần phải là a NVARCHAR.
James Anderson

4

Bất cứ khi nào bạn đặt một hàm xung quanh một cột `ISNULL (@var, table.col) ', ví dụ bạn loại bỏ khả năng sử dụng một chỉ mục của SQL. Đây thực sự là tùy chọn hoạt động tốt nhất nếu bạn muốn giữ nó trong một truy vấn duy nhất.

@var IS NULL or @var = table.col

Nếu không, bạn có hai lựa chọn. Đầu tiên là SQL động và câu trả lời của @ Mystagogue là đủ cho điều đó nếu không bạn có thể đặt vào hai truy vấn như thế này:

IF @var is NULL
     SELECT * FROM table
ELSE
     SELECT * FROM table WHERE @var = col

Trong cả định dạng này và SQL động, bạn thực sự sẽ có một kế hoạch truy vấn khác nhau cho mỗi truy vấn (có khả năng mang lại hiệu suất tốt hơn).


Sql trong câu hỏi không sử dụng ISNULL hoặc bất kỳ chức năng nào khác.
Mystagogue

@MystagogueI Tôi đang tham khảo một câu trả lời đã bị xóa.
Kenneth Fisher

0

Bạn có thể:

declare @myIdParam int = 1;

select *
from myTable
where nullif(@myIdParam, myTable.Id) is null;

Tuy nhiên, hãy nhớ rằng nullif()chức năng về cơ bản là bao bọc case. Đó không phải là viên đạn bạc loại bỏ một cách kỳ diệu ORvà do đó tăng tốc truy vấn.


sử dụng các hàm trong mệnh đề where có tác động tiêu cực đến hiệu suất vì nó ngăn chặn việc sử dụng các chỉ mục (hoặc vì vậy tôi đã nghe)
Mystagogue

@Mystagogue, vâng - nó thường làm cho các điều kiện tìm kiếm không phải là SARGable. Than ôi, đây là cách duy nhất tôi biết cách trả lời câu hỏi của bạn mà không cần dùng đến SQL động hoặc nhiều UNIONs. Khi tôi có nhiệm vụ chính xác này, tôi đã chọn SQL động.
Roger Wolf
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.