有没有更有效的方法来在这个特定的上下文中编写我的过滤器?

Is there a more efficient way to write my filters in this specific context?

我正在使用 SQL Server 2014,我的数据库中有一个 table (t1),其中包含一个数字列表(n1 到 n6)。摘录如下:

Id   n1   n2   n3   n4   n5   n6
100  3    10   26   31   35   39
101  1    3    11   22   36   40
102  10   19   20   30   39   40
103  6    12   25   27   28   33
...

假设我想通过排除存在数字 3 和 19 的行来过滤掉此 table,我的过滤代码将如下所示:

Select * from t1

WHERE [n1] not in (3,19)
AND [n2] not in (3,19)
AND [n3] not in (3,19)
AND [n4] not in (3,19)
AND [n5] not in (3,19)
AND [n6] not in (3,19)

预期输出:

Id   n1   n2   n3   n4   n5   n6
103  6    12   25   27   28   33
...

有没有更有效的方法来编写我的过滤器?

您的过滤器很好,但您可能会发现写成这样更简单:

where 3 not in (n1, n2, n3, n4, n5, n6) and
      19 not in (n1, n2, n3, n4, n5, n6)

因为您引用的所有六列都不等式,所以您无法真正提高性能。您可以修复数据模型,使列位于不同的行中——允许使用索引。

一个选项使用 not existsvalues():

select t.*
from mytable t
where not exists (
    select 1
    from (values(n1), (n2), (n3), (n4), (n5), (n6)) x(n)
    where n in (3, 19)
)

当列表中的列数 and/or 值增加时,这比您的原始查询更好地缩放 - 尽管这不一定更有效。

Demo on DB Fiddle:

 Id | n1 | n2 | n3 | n4 | n5 | n6
--: | -: | -: | -: | -: | -: | -:
103 |  6 | 12 | 25 | 27 | 28 | 33

将一组不需要的值放在 CTE 中并使用 Except 运算符

正如其他人所指出的,数据模型并不理想。

要解决 NOT IN 过滤器的低效问题,您可以像这样使用 EXCEPT 运算符:

--sample data
   WITH smple ( id, n1, n2, n3, n4, n5, n6) AS
    ( SELECT 100, 3, 10, 26, 31, 35, 39
    union all
    select 101,1,3,11,22,36,40
    union all
    select
    102,10,19,20,30,39,40
    union all
    select
    103,6,12,25,27,28,33
    ),
--end sample data
    not_vals (n) as (select 3 union all select 19 ) 
    SELECT
        s.*
    FROM
        smple s
    EXCEPT 
    SELECT
        s.*
    FROM
        smple s join not_vals nv on
                nv.n IN ( s.n1, s.n2, s.n3, s.n4, s.n5, s.n6)
     ;

从性能的角度看一下可以使用的各种方法的效率会很有趣。


最终解决方案应该具有良好的性能,因此相关子查询可能无法提供。

这是一个相关子查询:

--sample data
with smple ( id, n1, n2, n3, n4, n5, n6) AS
( SELECT 100, 3, 10, 26, 31, 35, 39
union all
select 101,1,3,11,22,36,40
union all
select
102,10,19,20,30,39,40
union all
select
103,6,12,25,27,28,33
),
--end sample data
not_vals (n) as (select 3 union all select 19 ) 
SELECT
    s.*
FROM
    smple s
WHERE
    NOT EXISTS (
        SELECT 1 FROM not_vals nv
        WHERE
            nv.n IN ( s.n1, s.n2, s.n3, s.n4, s.n5, s.n6)
    )
;