您几乎绝对应该使用带有两个选择的 IF 语句。例如
IF @Name IS NULL
BEGIN
SELECT *
FROM Person
END
ELSE
BEGIN
SELECT *
FROM Person
--WHERE Name LIKE '%' + @Name + '%'
WHERE Name = @Name
END
注意自从LIKE without wildcards it is no different to equals 以来,我已经改变了like to 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 更冗长,可能看起来它做了更多的工作,但实际上它做的工作少了很多,而且效率更高。