表函数中的条件UNION ALL

Rom*_*kar 16 sql t-sql sql-server sql-execution-plan sql-server-2016

因此用例如下 - 有一些参数,我想根据这些参数从一个表或另一个表中选择数据.

create table dbo.TEST1 (id int primary key, name nvarchar(128))
create table dbo.TEST2 (id int primary key, name nvarchar(128))
Run Code Online (Sandbox Code Playgroud)

所以我创建了这样的函数:

create function [dbo].[f_TEST]
(
    @test bit
)
returns table
as
return (
    select id, name from TEST1 where @test = 1

    union all

    select id, name from TEST2 where @test = 0
)
Run Code Online (Sandbox Code Playgroud)

当我使用常量运行它时,执行计划很棒 - 只扫描一个表

select * from dbo.f_TEST(1)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

但是,当我使用变量时,计划并不是那么好 - 两个表都被扫描

declare @test bit = 1

select * from dbo.f_TEST(@test)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

那么是否有任何提示(或技巧)强制SQL Server理解在某个查询中只应扫描一个表?

Luk*_*zda 13

如果你的功能是内联TVP(如例子)那么你可以使用:

declare @test bit = 1
select * from dbo.f_TEST(@test) OPTION (RECOMPILE);
Run Code Online (Sandbox Code Playgroud)

然后在这两种情况下,您将获得单个聚簇索引扫描.

DBFiddle演示

选项RECOMPILE:

编译查询计划时,RECOMPILE查询提示使用查询中任何局部变量的当前值,如果查询位于存储过程内,则传递给任何参数的当前值.