假设我们有这个表:
|------------------------------|
| col | data type |
|------------------------------|
| id | bigint |
| first_name | nvarchar |
| last_name | nvarchar |
| photo | binary |
|------------------------------|
好了,现在我们想要对这个表进行两次查询:
为此,我们要使用SP
第一种方法是这样的:
SELECT Top 50
id,
first_name,
last_name,
CASE WHEN @id IS NULL THEN null ELSE photo END as photo
FROM MyTable
WHERE @id IS NULL OR id=@id
,第二种方法是:
IF (@id IS NULL)
SELECT Top 50
id,
first_name,
last_name,
null as photo
FROM MyTable
ELSE
SELECT
id,
first_name,
last_name,
photo
FROM MyTable
WHERE id=@id
END
第二种方法显然会检查if条件一次并完成工作。
但我喜欢像第一种方法一样编写我的SP,我不知道sql server是否要检查每行的CASE WHEN @id IS NULL
,或者查询优化器是否会在没有CASE
的情况下优化查询?
编辑1:
我想知道第一个查询是否始终执行没有大小写?因为它正在检查一个不改变值且与任何列值无关的变量。
答案 0 :(得分:2)
你可以试试这个,这可以避免CASE
和IF
。不过,我承认,它有点神秘。
SELECT Top 50
id,
first_name,
last_name,
null as photo
FROM MyTable
WHERE @id IS NULL
UNION ALL
SELECT id,
first_name,
last_name,
photo
FROM MyTable
WHERE id = @id
答案 1 :(得分:1)
由于发布了一些答案,我决定自己检查一下。
-- table is not identical to yours, but it should do.
create table t1 (
id int identity primary key,
first_name varchar(50),
last_name varchar(50)
)
go
-- insert ~10,000,000 rows of randomly generated data.
with cte as (
select 1 as rn, newid() as first_name, newid() as last_name
union all
select t.rn + 1 as rn, newid() as first_name, newid() as last_name
from cte t
where t.rn < 10000000
)
insert into t1 (first_name, last_name)
select first_name, last_name
from cte
option (maxrecursion 0)
go
update statistics
go
declare @id int = 5000000
SELECT Top 50
id,
first_name,
last_name
FROM t1
WHERE @id IS NULL OR id = @id
go
执行时间:13秒
执行计划:
declare @id int = 5000000
SELECT
id,
first_name,
last_name
FROM t1
WHERE id=@id
go
执行时间:0秒
执行计划:
declare @id int = 5000000
SELECT Top 50
id,
first_name,
last_name
FROM t1
WHERE @id IS NULL
UNION ALL
SELECT id,
first_name,
last_name
FROM t1
WHERE id = @id
go
执行时间:0秒
执行计划:
declare @id int = 5000000
SELECT Top 50
id,
first_name,
last_name
FROM t1
WHERE id = COALESCE(@id, id)
go
执行时间:14秒
执行计划:
在@id
具有值的情况下,您在单个查询中统一逻辑的尝试和Hogan都不会执行单独的查询。在这两种情况下,您都可以看到查询基本上扫描整个聚簇索引,而不是执行更直接的索引搜索。
有趣的是,虽然Ann的执行计划似乎是最复杂的,但性能表明优化器能够以某种方式检测到@id
不为空并且使昂贵的集群索引短路在这种情况下扫描。
尽管如此,由于您已经在存储过程中,我觉得您应该坚持使用if-else
方法。似乎是最安全的方式。
答案 2 :(得分:0)
执行此操作的标准方法(将null参数默认为all)如下所示:
SELECT
id,
first_name,
last_name,
photo
FROM MyTable
WHERE id=COALESCE(@id,id)
根据我的经验,如果ID上有索引
,这会在所有主要平台上提供良好的性能