您几乎绝对应该使用带有两个选择的 IF 语句。例如
IF @Name IS NULL
BEGIN
SELECT *
FROM Person
END
ELSE
BEGIN
SELECT *
FROM Person
--WHERE Name LIKE '%' + @Name + '%'
WHERE Name = @Name
END
注意我已经改变了 like to equals 因为LIKE
没有通配符它与 equals , 没有什么不同,它在性能方面应该没有任何区别,但它可以防止下一个将阅读您的查询的人产生歧义。如果您确实想要非完全匹配,请使用注释掉WHERE
并根据需要删除通配符。
原因IF
是这两个查询可能有非常不同的执行计划,但是通过将它们组合到一个查询中,您会迫使优化器选择一个或另一个计划。想象一下这个模式:
CREATE TABLE Person
( PersonID INT IDENTITY(1, 1) NOT NULL,
Name VARCHAR(255) NOT NULL,
DateOfBirth DATE NULL
CONSTRAINT PK_Person_PersonID PRIMARY KEY (PersonID)
);
GO
CREATE NONCLUSTERED INDEX IX_Person_Name ON Person (Name) INCLUDE (DateOfBirth);
GO
INSERT Person (Name)
SELECT DISTINCT LEFT(Name, 50)
FROM sys.all_objects;
GO
CREATE PROCEDURE GetPeopleByName1 @Name VARCHAR(50)
AS
SELECT PersonID, Name, DateOfBirth
FROM Person
WHERE Name IN (SELECT Name FROM Person WHERE Name LIKE ISNULL(@Name, Name));
GO
CREATE PROCEDURE GetPeopleByName2 @Name VARCHAR(50)
AS
IF @Name IS NULL
SELECT PersonID, Name, DateOfBirth
FROM Person
ELSE
SELECT PersonID, Name, DateOfBirth
FROM Person
WHERE Name = @Name;
GO
现在,如果我使用值和不使用值运行这两个过程:
EXECUTE GetPeopleByName1 'asymmetric_keys';
EXECUTE GetPeopleByName1 NULL;
EXECUTE GetPeopleByName2 'asymmetric_keys';
EXECUTE GetPeopleByName2 NULL;
两个程序的结果是相同的,但是,对于第一个程序,我每次都得到相同的计划,但是对于第二个程序有两个不同的计划,这两个程序都比第一个程序更有效率。
如果您不能使用IF
(例如,如果您使用的是内联表值函数),那么您可以使用以下方法获得类似的结果UNION ALL
:
SELECT PersonID, Name, DateOfBirth
FROM Person
WHERE @Name IS NULL
UNION ALL
SELECT PersonID, Name, DateOfBirth
FROM Person
WHERE Name = @Name;
这不如使用 IF 高效,但仍然比您的第一个查询更有效。底线是更少并不总是更多,是的,使用IF
更冗长,可能看起来它正在做更多的工作,但实际上它做的工作少得多,而且效率更高。